2025年01月13日字节(本地生活)前端面试

目录

  1. 自我介绍
  2. 项目介绍(拷问)
  3. js事件循环
  4. 浏览器如何解析html文件
  5. 输入 url 到页面呈现的过程
  6. http与https,https为什么安全,证书是如何获取的?
  7. require引入与import的引入的区别
  8. vite 打包工具相比 webpack 优势
  9. 手写 promise
  10. 手写发布订阅模式

3. js事件循环

以下是对 JavaScript 事件循环的更深入解释:

基本概念
  • 单线程执行模型:JavaScript 是单线程的,即在同一时间内只能执行一个任务。这意味着 JavaScript 代码按顺序执行,不会出现多个任务同时执行的情况。但为了处理异步操作,JavaScript 引入了事件循环机制,使它可以在等待某些操作完成时继续执行其他代码。
核心组件
  • 执行栈(Call Stack)
    • 执行栈是一个后进先出(LIFO)的数据结构,用于存储当前正在执行的函数调用。
    • 当一个函数被调用时,它会被压入执行栈;当函数执行完成,它会从栈中弹出。
    • 例如:
function first() {
    second();
}
function second() {
    third();
}
function third() {
    console.log('Hello, World!');
}
first();
- 调用 `first()` 时,`first` 函数会被压入执行栈;`first` 函数调用 `second()`,`second` 函数会被压入执行栈;`second` 函数调用 `third()`,`third` 函数会被压入执行栈;`third` 函数执行并打印 `Hello, World!`,然后 `third` 函数从栈中弹出,接着 `second` 函数弹出,最后 `first` 函数弹出。
  • 任务队列(Task Queue)
    • 任务队列存储着等待执行的任务,主要是异步操作的回调函数。
    • 任务队列可以分为宏任务队列(Macrotask Queue)和微任务队列(Microtask Queue)。
宏任务与微任务
  • 宏任务(Macrotasks)

    • 常见的宏任务包括 setTimeoutsetIntervalsetImmediate(Node.js)、I/O 操作、UI 渲染等。
    • 宏任务的执行顺序是一个接一个的,即执行完一个宏任务后,才会开始执行下一个宏任务。
    • 例如,setTimeout 函数会将其回调函数添加到宏任务队列中,当达到设定的延迟时间后,该回调函数会等待被执行。
  • 微任务(Microtasks)

    • 常见的微任务包括 Promise.then()Promise.catch()process.nextTick(Node.js)、queueMicrotask 等。
    • 微任务的优先级高于宏任务。在当前宏任务执行结束后,会优先执行微任务队列中的所有微任务,直到微任务队列为空。
    • 例如,Promise.resolve().then() 会将其回调函数添加到微任务队列中,该回调函数会在当前宏任务完成后立即执行,而不是等待下一个宏任务。
事件循环的执行流程
  1. 检查执行栈是否为空。
    • 如果执行栈不为空,继续执行栈中的函数调用。
    • 如果执行栈为空,进入下一步。
  2. 检查微任务队列是否为空。
    • 如果微任务队列不为空,按顺序依次执行微任务队列中的任务,直到微任务队列为空。
    • 如果微任务队列也为空,进入下一步。
  3. 从宏任务队列中取出一个任务,将其添加到执行栈中并执行。
  4. 重复上述步骤。
示例代码及详细解释
console.log('Start');

setTimeout(() => {
    console.log('Timeout 1');
    Promise.resolve().then(() => {
        console.log('Promise inside Timeout 1');
    });
}, 0);

Promise.resolve().then(() => {
    console.log('Promise 1');
    setTimeout(() => {
        console.log('Timeout inside Promise 1');
    }, 0);
});

console.log('End');
  • 代码执行顺序如下:
    1. 首先,console.log('Start') 是同步代码,直接执行,输出 Start
    2. setTimeout(() => {...}, 0) 是宏任务,其回调函数被添加到宏任务队列中。
    3. Promise.resolve().then(() => {...}) 是微任务,其回调函数被添加到微任务队列中。
    4. console.log('End') 是同步代码,直接执行,输出 End
    5. 此时执行栈为空,检查微任务队列,发现 Promise.resolve().then(() => {...}) 的回调函数,执行该微任务,输出 Promise 1,并将另一个 setTimeout 回调添加到宏任务队列。
    6. 微任务队列已空,从宏任务队列中取出 setTimeout(() => {...}) 的回调函数,执行该宏任务,输出 Timeout 1,同时将内部的 Promise.then() 微任务添加到微任务队列。
    7. 再次检查微任务队列,执行内部的 Promise.then() 微任务,输出 Promise inside Timeout 1
    8. 最后,执行之前添加到宏任务队列的 setTimeout(() => {...}) 回调函数,输出 Timeout inside Promise 1
事件循环的重要性和应用场景
  • 重要性

    • 事件循环使 JavaScript 能够高效处理异步操作,避免因等待某些操作(如网络请求、文件读取等)而阻塞代码执行,保证程序的流畅性。
    • 理解事件循环有助于避免一些常见的异步编程错误,如竞态条件、回调地狱等。
  • 应用场景

    • 网络请求:当使用 fetchXMLHttpRequest 进行网络请求时,请求完成后的回调函数会被添加到任务队列中,等待执行。
    • 用户交互:点击事件、输入事件等用户交互的处理函数会被添加到任务队列中,在用户触发事件后等待执行。
    • 定时器操作:使用 setTimeoutsetInterval 等定时器,其回调函数会在设定的时间后添加到任务队列中。

在面试中,可以这样回答:“JavaScript 事件循环是一种处理异步操作的机制,它基于单线程执行模型。核心组件包括执行栈和任务队列,任务队列又分为宏任务队列和微任务队列。宏任务如 setTimeoutsetInterval 等,微任务如 Promise.then() 等。事件循环的执行流程是先检查执行栈是否为空,若为空,检查微任务队列,若微任务队列不为空,执行微任务直到为空,再从宏任务队列取一个任务执行,不断重复这个过程。这一机制使 JavaScript 可以在等待异步操作时继续执行其他代码,避免阻塞,同时保证了执行顺序。例如在处理网络请求、用户交互和定时器操作等场景中,事件循环能确保这些异步操作的回调函数在适当的时间得到执行,同时避免因等待而影响程序的流畅性。”

通过这样的详细解释和示例,可以清晰地阐述 JavaScript 事件循环的概念、流程、重要性和应用场景,让面试官了解你对该知识点的深入理解和掌握程度。

4. 浏览器如何解析html文件

以下是浏览器解析 HTML 文件的详细过程:

1. 字节流转换
  • 浏览器接收到 HTML 文件时,它是以字节流的形式存在的。首先,这些字节流会被转换为字符,根据文件的编码方式(如 UTF-8、UTF-16 等)将字节解码为字符。
2. 词法分析(标记化)
  • 浏览器会对字符进行词法分析,将字符流转换为一系列的标记(Tokens)。
  • 例如,将 标记为 StartTag:html,将 标记为 EndTag:html,将文本内容标记为 CharData 等。
  • 常见的标记类型包括:
    • StartTag:表示 HTML 元素的开始标签,如
    • EndTag:表示 HTML 元素的结束标签,如
  • CharData:表示元素内的文本内容,如 This is a div
  • Comment:表示 HTML 中的注释,如
  • 3. 语法分析(构建 DOM 树)
    • 浏览器将生成的标记进行语法分析,构建 DOM(Document Object Model)树。
    • 这个过程遵循 HTML 语法规则:
      • 当遇到 StartTag 时,会创建一个新的 DOM 节点,并将其添加到 DOM 树中。
      • 对于嵌套的元素,会将子元素添加到相应父元素的子节点列表中。
      • 例如,对于

        Hello

        1. 首先遇到 ,创建 html 节点作为根节点。
        2. 接着遇到 ,创建 body 节点并添加到 html 节点的子节点列表。
        3. 然后遇到

          ,创建 h1 节点并添加到 body 节点的子节点列表。

        4. 对于 HelloCharData,将其作为 h1 节点的文本内容。
        5. 最后遇到 ,完成节点的闭合和树的构建。
    4. 预加载扫描
    • 在构建 DOM 树的同时,浏览器会进行预加载扫描。
    • 会查找一些外部资源的引用,如 中的 style.css 中的 script.js
    • 这些资源会被添加到预加载队列中,以便后续快速加载。
    5. 处理脚本和样式
    • 对于

    你可能感兴趣的:(前端面试实战,前端,面试)