24秋招美团一面🦘「八股文+代码输出+算法题」

八股文

讲讲异步组件和路由懒加载?异步加载的过程是怎么样的?为什么在router中使用回调的方式引入组件就可以实现异步加载?假如一个页面有特别多的异步组件会带来什么问题?

其实异步组件和异步路由是一样的东西,异步路由引入的也还是对应的组件。

异步加载的过程涉及到JavaScript运行时、事件循环机制以及打包工具的配合工作。过程:

  1. 代码分割 :当我们在代码中使用import()函数异步加载组件时,打包工具(如Webpack或Rollup)会将这些组件作为单独的JavaScript文件(通常被称为"chunks")进行打包。
  2. 初始加载:在页面初始加载时,只有主bundle会被下载。主bundle中包含了应用的主要代码,但不包括异步组件的代码。
  3. 异步请求:当用户触发了需要异步组件的操作(如访问一个使用了路由懒加载的路由),JavaScript运行时会发送一个网络请求,请求异步组件对应的JavaScript文件。
  4. 下载和执行:浏览器下载异步组件对应的JavaScript文件,并执行其中的代码。这个过程可能会涉及到一些延迟,因为需要等待网络请求完成,并且JavaScript是单线程的,不能同时执行多段代码。
  5. 渲染组件:异步组件的代码被执行后,组件会被注册到Vue.js应用中,并触发视图的更新。Vue.js会创建一个新的组件实例,并将其渲染到页面上。

在这个过程中,打包工具起到了关键作用。它负责将代码分割成多个小文件,并在构建时生成一份映射表,这样JavaScript运行时就知道每个异步组件对应哪个文件。

同时,JavaScript的事件循环机制也在这个过程中发挥了作用。由于JavaScript是单线程的,它需要使用事件循环来处理异步操作。当我们使用import()函数加载一个组件时,这个操作会被放入微任务队列中。只有当当前的同步代码执行完毕后,才会执行微任务队列中的操作。这也是为什么异步组件不会立即被加载和渲染的原因。

过多的异步组件可能会导致的问题:

  • 网络请求过多导致阻塞、请求失败
  • 加载异步组件导致页面闪烁、抖动,影响用户体验
  • 每个异步组件都可能下载失败,一一提供错误处理比较复杂

Vuex 的底层原理是什么?有了解过设计模式吗?发布订阅模式?

笔者对 vuex 也仅限于使用所以答得并不太好,在掘金上找到一篇讲的比较好的文章Vuex核心源码解析之手写Vuex

使用方式

vuex 是个状态管理模式,其基本工作流程是:当用户修改状态的时候,如果是 同步 修改状态,会先提交(commit)触发 mutations方法,改变 Store实例中的状态,这也是 唯一 修改状态的途径,如果是 异步 的修改状态的方法,比如发起数据请求等,会提交 dispatch 触发 actions方法,然后在 actions方法 中通过 commit 触发 mutations方法 进而 更新Store实例的状态,然后再将 状态更新Vue组件中。如果我们的项目是大型的单页面应用,那么我们就需要使用vuex在组件外部管理状态,通过这个状态管理模式我们可以很轻松的实现组件之间的通信,这也是选择vuex的原因之一,当然vuex也有自己的缺陷,就是状态不能够持久化。

实现原理

Vuex实现响应式原理 通过在 install方法 内通过 vue的 mixin方法Store实例 注入到每个组件内,在 resetStoreVm方法内部主要是借助 vue本身的响应式原理 来实现状态的响应式,借助computed来实现 getters的缓存 效果,然后通过 发布订阅的思想 将用户定义的 mutationsactions 方法存储起来,当用户触发 commitdispatch 的时候就去 订阅mutationsactions 找出对应的方法。如果存在 模块嵌套 的情况下,首先,vuex内部会通过一个 moduleCollection类 将所有模块 格式化 为一个 树形结构,其次,通过 installModule方法 将格式化好的树形结构 安装Store实例上,最后,通过 resetStoreVm方法 借助 vue内部响应式的原理 将所有模块的状态都置为 响应式。vuex是 响应式 的同时还支持 插件 的使用,Store内部有 subscribe方法replaceState方法,通过这两个方法我们实现 vuex的状态的持久化,以上说明了 vuex是高度依赖 vue响应式插件系统的

哪里跌倒在哪里爬起来之手写发布订阅模式:

美团一面:你了解发布-订阅模式吗?「每天搞透一道JS手写题💪Day8」 - 掘金 (juejin.cn)

HTTP和HTTPS的区别是什么?SSL协议的加密方式是什么?

HTTP (端口号80)和HTTPS(端口号443)的主要区别在于安全性和数据传输方式。

HTTP(超文本传输协议)是一种用于分布式、协作式和超媒体信息系统的应用层协议。它以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息。

HTTPS(超文本传输安全协议)是一种透过计算机网络进行安全通信的传输协议,需要CA证书。HTTPS经由HTTP进行通信,但利用SSL/TLS来加密数据包。HTTPS的主要目的是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。

SSL (Secure Sockets Layer)安全套接层协议,目的是保证数据传输的安全和完整。SSL协议既用到了对称加密也用到了非对称加密 (公钥加密),在建立传输链路时,SSL首先对对称加密的密钥 使用公钥进行非对称加密 ,链路建立好之后,SSL对传输 内容使用对称加密。这样,既利用了非对称加密在公开环境下安全传输密钥的优点,又利用了对称加密算法在大量数据加密时的效率优势。

TCP 的三次握手?

TCP(传输控制协议)是一种面向连接的协议,它在数据传输之前需要在客户端和服务器之间建立连接。这个连接的建立过程就是我们所说的"三次握手"。以下是三次握手的具体步骤:

第一次握手:客户端将标志位SYN设置为1,随机产生一个值seq=J,并将该数据包发送给服务器,然后客户端进入SYN_SENT状态。

第二次握手:服务器收到客户端的SYN包,必须确认客户端的SYN,将标志位SYN和ACK都置为1,ack=J+1,同时为自己也要发送SYN请求信息,随机产生一个值seq=K,并将该数据包发送给客户端,此时服务器进入SYN_RCVD状态。

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=K+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

完成三次握手后,客户端与服务器就正式建立了连接,在这个状态下,双方都可以发送数据。

了解事件循环吗?微任务有哪些?

事件循环是JavaScript的执行机制。由于JavaScript是单线程的,事件循环机制可以解决JavaScript在处理高IO任务时可能出现的阻塞问题。

事件循环包括两种任务:宏任务和微任务。宏任务由宿主(浏览器/Node)发起,微任务由JavaScript自身发起。

微任务包括:

  • Promise.then()
  • process.nextTick(仅在Node.js环境中)
  • Object.observe(已废弃;被Proxy对象替代)
  • MutationObserver

执行顺序是:先执行同步代码,遇到异步宏任务则将异步宏任务放入宏任务队列中,遇到异步微任务则将异步微任务放入微任务队列中。当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行,微任务执行完毕后再将异步宏任务从队列中调入主线程执行,一直循环直至所有任务执行完毕。

代码输出题

结合刚才说的事件循环,判断下面的代码输出顺序

js 复制代码
console.log('start');

setTimeout(() => {
    console.log('Timeout1');
}, 1000);

Promise.resolve().then(() => {
    console.log('Promise1');
});

Promise.resolve().then(() => {
    console.log('Promise2');
    setTimeout(() => {
      Promise.resolve().then(() => {
        console.log('Promise3');
      })
      console.log('Timeout2');
    }, 0);
});

console.log('end');

打印顺序: start end Promise1 Promise2 Timeout2 Promise3 Timeout1

说明:

  1. 首先按顺序执行同步代码,打印 start 和 end,并且把异步任务分别放入宏任务和微任务队列中;
  2. 其次执行微任务队列中的回调,打印 Promise1 和 Promise2;
  3. 打印完 Promise2 之后,又向宏任务队列中推入了一个计时器;
  4. 此时宏任务队列中有两个计时器,优先执行延迟时间短的那个,打印了 Timeout2,并且向微任务队列中加入了要一个回调函数;
  5. 再次优先执行微任务队列中的回调,打印 Promise3。最后,打印 Timeout1。

这段代码输出什么?为什么会输出这样的结果?如何修改使其正常工作?

js 复制代码
for(var i = 0; i < 3; i++){
    setTimeout(function(){
        console.log(i)
    })
}

这段代码会输出三次 "3",因为 setTimeout 函数是异步的,当计时器执行时,for 循环已经结束,变量 i 的值为 3,并且 var 不存在块级作用域,因此三个计时器中的回调函数都会打印 3。

想要让这段代码顺序打印0,1,2,就要保证计时器中的 i 是当次循环的 i 值,这需要将这个 i 和计数器固定到一个作用域中。

有两种方法:一是直接将 var 修改为 letlet 关键字会创建块级作用域,在每次循环中 let 都会创建一个新的变量 i,并初始化其为当前的值;二是使用闭包给每一次循环创建一个新的作用域,代码如下:

js 复制代码
for(var i = 0; i < 3; i++){
    (function(i){
        setTimeout(function(){
            console.log(i)
        })
    })(i)
}

算法题

leetcode 102. 二叉树的层序遍历

js 复制代码
/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var levelOrder = function (root) {
    if (!root) return [];
    let queue = [];
    let res = [];
    queue.push(root);
    while (queue.length) {
        let arr = [];
        let len = queue.length;
        for (let i = 0; i < len; i++) {
            let node = queue.shift();
            arr.push(node.val);
            if (node.left) queue.push(node.left);
            if (node.right) queue.push(node.right);
        }
        res.push(arr);
    }
    return res;
};

写完之后会让你结合代码讲一下思路。

相关推荐
吕彬-前端19 分钟前
使用vite+react+ts+Ant Design开发后台管理项目(二)
前端·react.js·前端框架
小白小白从不日白40 分钟前
react hooks--useCallback
前端·react.js·前端框架
恩婧1 小时前
React项目中使用发布订阅模式
前端·react.js·前端框架·发布订阅模式
mez_Blog1 小时前
个人小结(2.0)
前端·javascript·vue.js·学习·typescript
孙小二写代码1 小时前
[leetcode刷题]面试经典150题之1合并两个有序数组(简单)
算法·leetcode·面试
珊珊而川1 小时前
【浏览器面试真题】sessionStorage和localStorage
前端·javascript·面试
森叶1 小时前
Electron 安装包 asar 解压定位问题实战
前端·javascript·electron
drebander1 小时前
ubuntu 安装 chrome 及 版本匹配的 chromedriver
前端·chrome
软件技术NINI1 小时前
html知识点框架
前端·html
深情废杨杨1 小时前
前端vue-插值表达式和v-html的区别
前端·javascript·vue.js