11.29面经(一面)

177 阅读15分钟

1.之前的项目上有什么难点吗

2.之前在项目中用到这个websocket是怎么用的

3.vue的响应式原理

vue 数据双向绑定原理是通过数据劫持+发布订阅者的方式来实现的,首先是通过 ES6 提供的 Object.defineProperty()方法来劫持监听各属性的 getter 和 setter,并在当监听的属性发生变动时通知订阅者,是否需要更新,若更新就会执行对应的更新函数。

常见的数据劫持有两种方式,第一种是 Vue2 中的 object.defineProperty,第二种是 ES2015 中新增的 Proxy,Vue3 中就是通过 Proxy 代替 Object.defineProperty

完成一个数据的双向绑定需要做到如下步骤:

1.利用 Proxy 或 Object.defineProperty 生成的 observer 针对对象/对象的属性进行劫持,在属性发生变化后通知订阅者

2.解析器 complie 解析模板中的 Directive 指令,收集指令所有的方法和数据,等待数据发生变化然后进行渲染。

3.watcher 属于 observer 和 complie 的桥梁,接收到 observer 产生的数据变化并根据 complie 提供的指令进行视图渲染,使得数据变化促使视图变化

4.diff算法源码有看过吗

5.webpack打包的原理过程

1、初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数

2、开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译

3、确定入口:根据配置中的 entry 找出所有的入口文件

4、编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理

5、完成模块编译:在经过第 4 步使上述 loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系

6、输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加载到输出列表,这步是可以修改输出内容的最后机会

7、输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统,在以上过程中,webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果

6.webpack的性能优化主要有哪些手段

  • JS 代码压缩:terser 是一个 JavaScript 的解释、绞肉机、压缩机的工具集,可以帮助我们压缩、丑化我们的代码,让 bundle 更小。
  • CSS 代码压缩:CSS 压缩通常是去除无用的空格等,因为很难去修改选择器、属性的名称、值等。
  • Html 文件代码压缩:使用 HtmlWebpackPlugin 插件来生成 HTML 的模板时候,通过配置属性 minify 进行 html 优化。
  • 文件大小压缩:对文件的大小进行压缩,减少 http 传输过程中宽带的损耗。
  • 图片压缩
  • Tree Shaking:Tree Shaking 是一个术语,在计算机中表示消除死代码,依赖于 ES Module 的静态语法分析(不执行任何的代码,可以明确知道模块的依赖关系)
  • 在 webpack 实现 Tree shaking 有两种不同的方案:
  • 1.usedExports:通过标记某些函数是否被使用,之后通过 Terser 来进行优化的
  • 2.sideEffects:跳过整个模块/文件,直接查看该文件是否有副作用
  • 代码分离:将代码分离到不同的 bundle 中,之后我们可以按需加载,或者并行加载这些文件
  • 默认情况下,所有的 JavaScript 代码(业务代码、第三方依赖、暂时没有用到的模块)在首页全部都加载,就会影响首页的加载速度
  • 代码分离可以分出出更小的 bundle,以及控制资源加载优先级,提供代码的加载性能。
  • 内联 chunk:可以通过 InlineChunkHtmlPlugin 插件将一些 chunk 的模块内联到 html,如 runtime 的代码(对模块进行解析、加载、模块信息相关的代码),代码量并不大,但是必须加载的

7.浏览器中从输入www.baidu.com按下回车后都会发生什么?

输入地址,按下回车;

  • DNS 查询服务器 IP;
  • TCP 三次握手;
  • TLS 协商;
  • 发送初始 GET 请求到 HTML 文件;
  • 将 HTML 内容构建成 DOM 树;
  • 将 CSS 内容构建成 CSSOM 树;
  • 将 DOM 树和 CSSOM 树合成渲染树;
  • 根据渲染树进行页面元素的布局;
  • 对渲染树进行分层操作,并生成分层树;
  • 为每个图层生成绘制列表,并提交到合成线程;
  • 合成线程将图层分成不同的图块,并通过栅格化将图块转化为位图;
  • 合成线程给浏览器进程发送绘制图块指令;
  • 浏览器进程会生成页面,并显示在屏幕上。

8.http和https的区别

  1. http:
  • HTTP 超文本传输协议 ,应用层协议。主要用于 Web 上传输超媒体文本的底层协议,经常在浏览器和服务器之间传递数据。通信就是以纯文本的形式进行。
  • 无状态是 HTTP 协议对客户端请求状态没有进行存储,比如每次请求都需要重新登录。
  • 无连接主要是限制每次连接只处理一个请求。每次请求都是客户发起请求,服务端响应请求,然后就断开连接。这期间就是通过三次握手建立连接,四次挥手断开连接。每次请求即便是多次请求并请求同一个资源,服务端都无法判断是否是相同请求,都需要重新响应请求。
  • 所以,为了解决客户端和服务端保持会话连接,通过 cookie 和 session 来记录 http 状态。
  • HTTP 的其他特点是简单快速,只需传送方法和路径就可以向服务端进行请求;还有支持传输任意类型的数据对象。
  1. https:
  • https 是 http 的“升级”版本:HTTPS = HTTP+ SSL/TLS
  • SL 是安全层,TLS 是传输层安全,是 SSL 的继承。使用 SSL 或 TLS 可确保传输数据的安全性。
  • 使用 HTTP 可能看到传输数据是: “这是明文信息”
  • 使用 HTTPS 可能看到: “283hd9saj9cdsncihquhs99ndso”
  • HTTPS 传输的不再是文本,而是二进制流,使得传输更高效,且加密处理更加安全。
  1. HTTPS 的工作流程:
  • 1、客户端请求 HTTPS 请求并连接到服务器的 443 端口,此过程和请求 HTTP 请求一样,进行三次握手;
  • 2、服务端向客户端发送数字证书,其中包含公钥、证书颁发者、到期日期
  • 现比较流行的加解密码对,即公钥和私钥。公钥用于加密,私钥用于解密。所以服务端会保留私钥,然后发送公钥给客户端。
  • 3、客户端收到证书,会验证证书的有效性。验证通过后会生成一个随机的 pre-master key。再将密钥通过接收到的公钥加密然后发送给服务端
  • 4、服务端接收后使用私钥进行解密得到 pre-master key
  • 5、获得 pre-master key 后,服务器和客户端可以使用主密钥进行通信。
  1. HTTP 与 HTTPS 区别:
  • 加密: HTTPS 是 HTTP 协议的更加安全的版本,通过使用 SSL/TLS 进行加密传输的数据;
  • 连接方式: HTTP(三次握手)和 HTTPS (三次握手+数字证书)连接方式不一样;
  • 端口: HTTP 默认的端口是 80 和 HTTPS 默认端口是 443
  1. HTTP2 是什么?
  • HTTP/2 超文本传输协议第 2 版,是 HTTP/1.x 的扩展。所以 HTTP/2 没有改动 HTTP 的应用语义,仍然使用 HTTP 的请求方法、状态码和头字段等规则。
  • 它主要修改了 HTTP 的报文传输格式,通过引入二进制分帧层实现性能的提升。
  • 现有很多主流浏览器的 HTTPS/2 的实现都是基于 SSL/TLS 的,所以基于 SSL/TLS 的 HTTP/2 连接建立过程和 HTTPS 差不多。在建立连接过程中会携带标识期望使用 HTTP/2 协议,服务端同样方式回应。

9.浏览器的缓存机制

浏览器缓存分为强缓存和协商缓存

强缓存:是利用 http 的返回头中的 Expires 或者 Cache-Control 两个字段来控制的,用来表示资源的缓存时间。 Expires 缓存过期时间,用来指定资源到期的时间,是服务器端的具体的时间点。也就是说, Expires=max-age + 请求时间,需要和 Last-modified 结合使用。但在上面我们提到过, cache- control 的优先级更高。 Expires 是 Web 服务器响应消息头字段,在响应 http 请求时告诉浏览 器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。 Cache-Control Cache-Control 是一个相对时间,例如 Cache-Control:3600,代表着资源的有效期是 3600 秒。由于是相对时间,并且都是与客户端时间比较,所以服务器与客户端时间偏差也不会导致问 题。 Cache-Control 与 Expires 可以在服务端配置同时启用或者启用任意一个,同时启用的时候 Cache-Control 优先级高。

协商缓存: 304 在第一次请求时候, 返回状态码 200, 和响应头中返回 cache-Control, 控制缓存使用 的时间/方式(私有缓存和共享缓存), 在第二次发起请求时, 先查看 max-age 如果过期了, 在请 求头设置 If-None-Match 等于刚刚 Etag 的值, 去后台对比, 如果 etag 值相同证明后端没更新, 所以返回 304 状态, 前端提取本地的缓存继续使用. (也是协商缓存)

10.防抖和节流

一、防抖

1、概念 防抖策略(debounce):当事件被触发后,延迟 n 秒后再执行回调。若在 n 秒内又被触发,则重新计时。

2、理解 多次触发只执行一次,比如王者荣耀回城,只有经过 8 秒才能触发回城,8 秒途中再次触发回城或中断,都需要重新等待 8 秒才能回城

3、应用场景 登录、发短信等按钮避免用户点击太快,导致发送了多次请求,需要防抖。

二、节流

1、概念 在规定的时间范围内不会重复触发回调,只有大于这个时间间隔才会触发,把频繁触发变为少量触发。

2、理解 一个周期只执行一次,比如王者荣耀技能,只有经过技能冷却时间,,才能再次使用

3、应用场景

① 鼠标连续不断地触发某事件(如点击),只在单位时间内只触发一次;

② 懒加载时要监听计算滚动条的位置,但不必每次滑动都触发,可以降低计算的频率,而不必去浪费 CPU 资源;

③ 浏览器 input 搜索框展示下拉列表,需要节流,也可以使用防抖 防抖是触发间隔大于 timer 才会触发,所以每次在小于间隔 time 要清除定时器; 节流是不管 time 内触发多少次,只会每间隔 time 时间才会触发一次,所以用 return

总结:防抖是限制操作,节流是减少操作

11.浏览器中的事件循环机制(eventloop)

在任务队列中,任务分为宏任务和微任务。

常见的宏任务有:script 全文,setTimeout,setTimeInterval,setImmediate,ui 渲染,I/O。

常见的微任务有:Promise,process.nextTick,MutationObserver(html5 新特性)。

执行宏任务,然后执行该宏任务产生的微任务,若微任务在执行过程中产生了新的微任务,则继续执行微任务,微任务执行完毕后,再回到宏任务中进行下一轮循环。

12.nextTick()的使用和原理

nextTick 是等待下一次 DOM 更新刷新的工具方法。

Vue 有个异步更新策略,意思是如果数据变化,Vue 不会立刻更新 DOM,而是开启一个队列,把组件更新函数保存在队列中,在同一事件循环中发生的所有数据变更会异步的批量更新。这一策略导致我们对数据的修改不会立刻体现在 DOM 上,此时如果想要获取更新后的 DOM 状态,就需要使用 nextTick。

开发时,有两个场景我们会用到 nextTick:

created 中想要获取 DOM 时; 响应式数据变化后获取 DOM 更新后的状态,比如希望获取列表更新后的高度。

nextTick 签名如下:function nextTick(callback?: () => void): Promise 所以我们只需要在传入的回调函数中访问最新 DOM 状态即可,或者我们可以 await nextTick()方法返回的 Promise 之后做这件事。

在 Vue 内部,nextTick 之所以能够让我们看到 DOM 更新后的结果,是因为我们传入的 callback 会被添加到队列刷新函数(flushSchedulerQueue)的后面,这样等队列内部的更新函数都执行完毕,所有 DOM 操作也就结束了,callback 自然能够获取到最新的 DOM 值。

13.watch和computed的区别以及选择?

计算属性可以从组件数据派生出新数据,最常见的使用方式是设置一个函数,返回计算之后的结果,computed 和 methods 的差异是它具备缓存性,如果依赖项不变时不会重新计算。侦听器可以侦测某个响应式数据的变化并执行副作用,常见用法是传递一个函数,执行副作用,watch 没有返回值,但可以执行异步操作等复杂逻辑。 计算属性常用场景是简化行内模板中的复杂表达式,模板中出现太多逻辑会是模板变得臃肿不易维护。侦听器常用场景是状态变化之后做一些额外的 DOM 操作或者异步操作。选择采用何用方案时首先看是否需要派生出新值,基本能用计算属性实现的方式首选计算属性。 使用过程中有一些细节,比如计算属性也是可以传递对象,成为既可读又可写的计算属性。watch 可以传递对象,设置 deep、immediate 等选项。 vue3 中 watch 选项发生了一些变化,例如不再能侦测一个点操作符之外的字符串形式的表达式; reactivity API 中新出现了 watch、watchEffect 可以完全替代目前的 watch 选项,且功能更加强大。

14.vite和webpack的区别

  • ⭐ 构建速度 ⭐
  • Webpack: Webpack 的构建速度相对较慢,尤其在大型项目中,因为它需要分析整个依赖图,进行多次文件扫描和转译。
  • Vite: Vite 以开发模式下的极速构建著称。它利用 ES 模块的特性,只构建正在编辑的文件,而不是整个项目。这使得它在开发环境下几乎是即时的。
  • ⭐ 开发模式 ⭐
  • Webpack: Webpack 通常使用热模块替换(HMR)来实现快速开发模式,但配置相对复杂。
  • Vite: Vite 的开发模式非常轻量且快速,支持 HMR,但无需额外配置,因为它默认支持。
  • ⭐ 配置复杂度 ⭐
  • Webpack: Webpack 的配置相对复杂,特别是在处理不同类型的资源和加载器时。
  • Vite: Vite 鼓励零配置,使得项目起步非常简单,但同时也支持自定义配置,使其适用于复杂项目。
  • ⭐ 插件生态 ⭐
  • Webpack: Webpack 拥有庞大的插件生态系统,适用于各种不同的需求。
  • Vite: Vite 也有相当数量的插件,但相对较小,因为它的开发模式和构建方式减少了对一些传统插件的需求。
  • ⭐ 编译方式 ⭐
  • Webpack: Webpack 使用了多种加载器和插件来处理不同类型的资源,如 JavaScript、CSS、图片等。
  • Vite: Vite 利用 ES 模块原生支持,使用原生浏览器导入来处理模块,不需要大规模的编译和打包。
  • ⭐ 应用场景 ⭐
  • Webpack: 适用于复杂的大型项目,特别是需要大量自定义配置和复杂构建管道的项目。
  • Vite: 更适用于小到中型项目,或者需要快速开发原型和小型应用的场景。
  • ⭐ 打包原理 ⭐
  • Webpack: Webpack 的打包原理是将所有资源打包成一个或多个 bundle 文件,通常是一个 JavaScript 文件。
  • Vite: Vite 的打包原理是保持开发时的模块化结构,使用浏览器原生的导入机制,在生产环境中进行代码分割和优化

15.this的绑定

  • 默认绑定
  • 隐式绑定
obj = {
     name:'Jiang',
     foo:function(){
       console.log(this)
     }
}
obj.foo();// obj
  • 显示绑定
function sum(num1,num2,num3){
    console.log(num1+num2+num3,this)
}
sum();// this 指向 windows 对象

sum.apply('apply',20,30,40);// this 指向 apply 对象
sum.call('call',[20,30,40]);// this 指向 call 对象
// 这也是 apply 和 call 的区别 他们都能自己决定 this 绑定的对象 但是传参方式有所区别

function foo(){
    console.log(this)
}

newFoo = foo.bind('aaaa'); // bind 也是显式绑定传入的参数就是绑定的 this 对象
newFoo();// 此时默认绑定和显式绑定冲突(显式绑定优先级更高)
  • new 绑定:
function Person(name,age){
    this.name = name;
    this.age = age;
}

p1 = new Person('Jiang',18);
p2 = new Person('kobe',18);

// Person 实际上会返回一个 this 对象 我们通过 p1 p2 来接收这个 this 对象

优先级:new>显式(apply/call/bind)>隐式绑定>默认绑定

间接函数的引用是独立调用函数 this 指向 windows