• Home
  • Archives
  Evan的博客
  • Home
  • Archives
  • 面试
  • 原理笔记
  • 项目实践
  • 其他

大前端相关面试题

2020/10/10 posted in  面试

其他类型的常见面试题:

  • 常见 HTML 和 CSS 面试题
  • 常见 JS 面试题
  • 常见 Vue 面试题
  • 常见性能相关面试题
  • 常见大前端相关面试题

近两年大前端相关的话题越来越多。所谓大前端,我的理解是对前端工程师知识体系中广度的考核。尤其是 node 诞生之后,JS 能干的东西越来越多,简单的如写个页面,复杂的甚至有 NodeOS 这种操作系统的玩意。

如果你想进大厂或者一些比较好的独角兽公司,只会敲一个页面是远远不够的。

  • 你可能需要掌握 Node 的知识,不一定是写后端,也有可能需要 ssr 同构,或者自定义打包工具,亦或者是写个 BFF
  • 你可能需要掌握一些运维的知识,比如会一些 Linux 的命令和一些如 Docker 等部署的知识
  • 你可能需要掌握一些数据结构和面向对象的编程习惯,或许你需要封装一些库或者 SDK
  • 你可能需要对整个前端体系有一定的了解,以便在性能和工程化上能有一些操作
  • 你可能需要......

1. 什么是MVC

MVC是 Model-View-Controller 的简称

  1. Model 是模型,是数据
  2. View 是视图
  3. Controller 是控制器

Controller 承接 View 和 Model,MVC 模型中通信是单向的,Controller 需要处理 Model 的业务变更,然后通知 View 你要如何去更新视图,Controller 容易变得过于庞大和臃肿

2. 什么是MVVM

MVVM是 Model-View-ViewModel 的简称

  1. Model 是模型,是数据
  2. View 是视图
  3. ViewModel 代替了 Controller,最大的特点就是双向通信,不像 Controller 需要通知 View 和 Model 并且做业务逻辑。ViewModel 只需要通知 View 和 Model 彼此发生更改就行了

比如 Vue 中,View 就是 template,Model 就是 Vuex,而 ViewModel 就是 Vue实例。当 View 接收到不同的用户交互的时候,Vue 实例告知 Vuex 如何修改 state;当Vuex 中的 state 变了的时候,Vue 实例修改虚拟 dom 然后让 template 发生变更更改视图

3. webpack tree shaking原理,是靠什么才能实现

tree shaking就是在打包过程中,把一些引入的依赖中又没用到的函数给去除掉,以减少打包的体积

tree shaking的消除原理是依赖于ES6的模块特性。

ES6 module有几个特性:

  1. 只能作为模块顶层的语句出现
  2. import 的模块名只能是字符串常量
  3. import binding 是 immutable的

和CommonJS不同,ES6是在解释阶段就确定依赖关系的,和运行时的状态无关,所以可以进行可靠的静态分析

分析过后就能精简代码,删掉如下代码:

  1. 代码不会被执行,不可到达
  2. 代码执行的结果不会被用到
  3. 代码只会影响死变量(只写不读)

4. webpack的构建原理,webpack的loader和plugin的区别

webpack构建主要有以下几步

  1. webpack.config.js结合命令行的参数,解析entry的入口文件
  2. 得到entry的ast树之后,遍历ast树,确定依赖
  3. 将ast解析成es5,并且递归解析所有依赖

Webpack是一种打包工具,它能将各种文件,按分类、逻辑打包,整合进一个或多个bundle.js之中。

loader简单来说就是翻译器,讲特定的文件按照特定的解释方式加载,打包

plugin简单来说就是在webpack打包的过程中,特定的时间节点做一些事情,已达到扩展webpack能力的目的。比如在打包前,把文件统一放到某个目录,或者打包后做一些什么操作之类的

5. 什么是进程,什么是线程

进程是资源分配的最小单位,线程是CPU调度的最小单位,进程和线程都是一个时间段的描述,是CPU工作时间段的描述,不过是颗粒大小不同

进程能独立拥有分配给自己的资源,而线程是进程的基础上的一次程序运行的单位

  1. 一个程序可以开启多个进程,比如浏览器一个tab就是一个进程,同时还有主进程,GPU进程等
  2. 一个进程可以有多个线程,比如一个tab有UI线程,有JS线程
  3. 所谓的单线程就是一个任务只能有一个线程在跑,多线程就是一个任务可以细分多个部分同时跑

6. 什么是并发,什么是并行

  1. 并发是宏观概念,我分别有任务 A 和任务 B,在一段时间内通过任务间的切换完成了这两个任务,这种情况就可以称之为并发。

  2. 并行是微观概念,假设 CPU 中存在两个核心,那么我就可以同时完成任务 A、B。同时完成多个任务的情况就可以称之为并行。

7. Performance API和常见的性能监控数据

浏览器提供一个 window.performance.timing 的api,用来提供一些特殊时间点的时间戳,用来追踪性能,包括dns,tcp/ip,首包响应时间,dom解析时间等

8. 谈下对serverless架构的理解

顾名思义,serverless架构即无服务架构。它的核心思想是FaaS,函数即服务。意思是服务器资源是根据函数访问量来重新分配再收费的。

比如有一个500pv的博客项目,如果部署在一台服务器上,可能大多数时间是没人访问的,资源就白白浪费了。而serverless就是当有人访问的时候启动服务,开始计费。没人访问就停掉服务。

传统的云服务的部署流程是这样的:

  1. 本地开发,构建包或者docker
  2. 推送到云服务器,服务器部署

serverless就不需要,直接推送到服务器,有人访问就访问最新代码,没人访问就停用服务。

serverless有优点也有缺点。优点是部署方便,按需分配资源,而且一般的服务商也会提供服务器的配套服务,比如各类数据库,想用什么就用什么,按需付费即可

缺点是serverless有一定的冷启动时间。因为它是FaaS的,没人用就停用,那有人访问的时候就需要一个启动时间。AWS提供的serverless宣称的时间能在50ms内,不过实际情况要考虑到网络波动等等,有一定的性能损耗。而且这是node作为服务的情况下,如果是java这种依赖虚拟机的就更蛋疼了。此外serverless几乎是和厂商绑定的,你用了谁家的serverless服务,也就依赖了谁家的底层数据,配套设施服务(毕竟都是同一台机器,或者说同一个厂商的集群)当要迁移的时候就会有麻烦。对于试水小应用,博客,或者初创企业来说,serverless很方便,但是对一个大型应用和完善的服务而言,serverless也有可能让扩容迁移变得麻烦。

9. 谈谈v8的垃圾回收机制

v8引擎根据内存占用时间,将垃圾回收有两种:新生代回收和老生代回收

  • 新生代管理短时间占用内存空间的引用,老生代管理长时间占用内存空间的引用
  • 默认情况下,32位系统新生代内存大小为16MB,老生代内存大小为700MB,64位系统下,新生代内存大小为32MB,老生代内存大小为1.4GB。

新生代的垃圾回收有两个空间,第一个是FROM空间(被使用),第二个是TO空间(空闲)。当垃圾回收机制进来看什么内存空间没有引用的时候,把没有引用的空间打上标记,然后把其他引用移动到空闲的TO空间中,然后清空FROM空间。这时候FROM空间和TO空间互换。当下一轮垃圾回收进来,也是如此,然后互换空间

老生代只有一个空间,每次垃圾回收进来就标记上已经没引用的内存空间,然后删掉。但是这样有个问题就是被删掉的空间可能是碎片状的,会存在浪费。于是多了一个步骤,先把还有用的内存空间移动到一边,然后把剩余的全部干掉。

也就是说,新生代只复制活着的对象,而老生代只清除死了的对象。活对象在新生代中只占较少部分,死对象在老生代中只占较少部分,这就是两种回收方式都能高效处理的原因。

10. 说说rollup和webpack的异同和优缺点

rollup的特点

  1. 更适合构建 lib
  2. 默认采用 esm
  3. 打包的体积更小

一般打包库用rollup,因为他简单易用,打包体积小。打包应用用webpack,因为webpack功能齐全,调试方便,社区生态健全

11. webpack 的 import 打包后变成什么,基于什么协议,如何加载

打包后会变成key value的形式,key是路径,value是模块的闭包函数

基于CMD协议的,也就是就近依赖

cmd是就近依赖,amd是提前依赖

12. v8的排序算法是怎么实现的

旧版本的v8引擎的sort是采用插入和快排的。

  • 对于长度小于 10 的数组采用插入排序
  • 长度大于 10 的数组采用快排

新版本之后采用了一种混合排序

  • 首先根据当前的数组总大小,计算出一个最小子数组长度minArrLen
  • 然后在数组中找到一个已经排好序的子序列,如1,17,36,8那子序列为 [1,17,36]
  • 然后对子序列执行插入排序,填充到minArrLen的长度
  • 重复执行找出子序列的操作,整个数组变成若干个已经排序好的子序列
  • 对这堆子序列执行归并排序

13. webpack中hash,chunk hash,content hash有什么区别

无论是什么hash,只要开启了hash,通过webpack构建之后,生成对应文件名自动带上对应的MD5值

  1. hash

hash的维度是整个webpack构建过程。在同一次构建中,所有的文件用的都是同一个hash。

只要有文件发生变更,那么这次构建的hash值就发生变更,然后所有打包出来的文件都用这个 hash。无论其自身是否有变更。这无疑是不利于缓存的,没变更的文件也被替换了hash

  1. chunk hash

webpack构建的过程中,会根据entry的依赖关系来确定不同的chunk

// 在这个例子中,mysdk会当成一个独立的chunk打包
module.exports = {
  mode: "production",
  entry: {
    index: "./src/index.js",
    vender: "./mysdk.js"
  },
  output: {
    filename: "[name].[chunkhash].js" // hash => chunkhash
  }
}

chunk hash的维度是根据chunk来定义的。对上面的例子而言,vender会被打进一个chunk,index被打进一个chunk。其中一个chunk发生了变更,其chunk hash会随之变更,但是不影响其他chunk

这样的好处就是利于缓存。比如index是业务代码,某次发版之后内容变更,chunk hash跟着变更。但是mysdk是比较稳定的sdk内容,不随着业务变更,那它的chunk hash还是保留了上次的结果

  1. content hash

content hash其实是一些插件自带的hash类型,比如 MiniCssExtractPlugin 就有content hash。它的纬度是文件内容本身,大部分时候指的是css。

比如一个js 引入了某个css。我们先看看chunk hash的情况

  • 假设js内容变更,css内容不变更
  • js内容变更了,那chunk hash自然变更
  • 因为这个js和css是同一个chunk,所以css的chunk hash也是变更的

如果用的是content hash

  • 检测到css内容没有发生变更,那么js的hash变更,css的hash不变更

14. 什么是webpack 的 scope hoisting

webpack作用域提升,指的是构建完的文件由多个函数合并到一个函数中。实现这个能力需要依靠ES6 Module的静态导入能力确定依赖关系

// 类似这样两个fn
function fn1() {
    // ...
}

function fn2() {
    // ...
}

// 合并成
function fn() {
    // run fn1 code
    // run fn2 code
}

15. webpack的source map 原理是什么

source map是个很复杂的过程,他的作用是定位源码压缩前的位置。原理是利用VLQ编码

16. node 为什么适合高并发

一般来说IO操作都是阻塞线程的,比如读写数据库,网络IO,读写文件等。大部分语言采用的策略是多线程处理。

但是对node来说,js是单线程的。node的解决方案是事件队列,也就是所谓的事件驱动。当遇到IO处理时,主线程将在线程池中请求一个线程资源,然后将相关的处理交给异步线程去做。当异步线程处理完后,线程归还线程池,事件回调推入事件队列

当主线程代码执行完毕之后,会进入一个 EventLoop 的阶段,处理timer,io cb,轮询结果,check等几个阶段。

« 前端面经复盘

常见 HTML 面试题 »

Evan的博客

Evan 的博客 - 非典型码农,bug永动机
Instagram Weibo GitHub Email RSS

Categories

面试 原理笔记 项目实践 其他 JS Vue 性能优化 算法 计算机网络

Recent Posts

  • 从 HTTP 发展历程重学计算机网络
  • 应届前端的逆袭(中)
  • 应届前端的逆袭(上)
  • 应届前端的逆袭(下)
  • 前端面经复盘

Copyright © 2015 Powered by MWeb,  Theme used GitHub CSS.