事件循环

JavaScript 的事件循环(Event Loop)是其处理异步操作的核心机制。 尽管 JavaScript 是单线程的,但通过事件循环,JavaScript 能够高效地处理并发任务,避免阻塞主线程。

1. 事件循环的基本概念

事件循环是一种机制,允许 JavaScript 执行异步任务而不阻塞主线程。 它通过将异步任务分配到任务队列中,并在主线程空闲时执行这些任务,从而实现非阻塞的异步操作。

2. 任务队列的分类

JavaScript 将任务分为两类:宏任务(Macro Task)和微任务(Micro Task)。

  • 宏任务(Macro Task):

    • 包括整体脚本(script)、setTimeoutsetIntervalsetImmediate、I/O 操作、UI 渲染等。

  • 微任务(Micro Task):

    • 包括 Promise 的回调、MutationObserverprocess.nextTick(Node.js 环境)等。

3. 事件循环的执行流程

事件循环的执行流程如下:

  1. 执行同步代码:

    • 首先执行整体脚本中的同步代码。

  2. 执行微任务:

    • 同步代码执行完毕后,立即执行微任务队列中的所有任务。

  3. 渲染更新:

    • 在微任务执行完毕后,浏览器可能会进行页面渲染更新。

  4. 执行宏任务:

    • 最后,执行宏任务队列中的任务。

需要注意的是,微任务的执行优先级高于宏任务,即在每次事件循环中,微任务会在宏任务之前执行。

4. 事件循环的示意图

以下是事件循环的简化示意图:

+-------------------+
|  执行同步代码      |
+-------------------+
|  执行微任务队列    |
+-------------------+
|  渲染更新(可选)  |
+-------------------+
|  执行宏任务队列    |
+-------------------+

5. 实际示例

以下是一个示例,展示了事件循环的执行顺序:

console.log("同步代码1");

setTimeout(() => {
  console.log("宏任务1");
  Promise.resolve().then(() => {
    console.log("微任务1");
  });
}, 0);

Promise.resolve().then(() => {
  console.log("微任务2");
});

console.log("同步代码2");

执行顺序:

  1. 执行同步代码:'同步代码1''同步代码2'

  2. 执行微任务队列中的任务:'微任务2'

  3. 执行宏任务队列中的任务:'宏任务1'

  4. 执行宏任务中的微任务:'微任务1'

输出结果:

同步代码1
同步代码2
微任务2
宏任务1
微任务1

6. 微任务和宏任务的优先级

微任务的优先级高于宏任务,即在每次事件循环中,微任务会在宏任务之前执行。 这意味着,如果在宏任务中添加了微任务,这些微任务会在当前宏任务执行完毕后立即执行,而不会等到下一个宏任务。

7. 浏览器与 Node.js 的差异

浏览器和 Node.js 都采用事件循环机制,但在实现细节上有所不同。 例如,浏览器的事件循环包括渲染阶段,而 Node.js 的事件循环则包括 I/O 阶段。 此外,Node.js 提供了 process.nextTick,用于在当前操作完成后、事件循环的其他阶段之前执行回调。

8. 参考资料

通过理解事件循环机制,开发者可以更好地编写高效的异步代码,提升应用的性能和用户体验。

最后更新于

这有帮助吗?