跳到主要内容

事件循环

前端的 Event Loop(事件循环) 是 JavaScript 实现异步编程的核心机制。虽然 JavaScript 本身是单线程语言,但通过 Event Loop,它能够高效地处理异步任务(如定时器、网络请求、用户交互等),而不会阻塞主线程。


一、为什么需要 Event Loop?

  • JavaScript 运行在浏览器的主线程(或 Node.js 的主事件循环线程)。
  • 如果所有代码都同步执行,遇到耗时操作(如 setTimeoutfetchclick 事件),页面就会“卡死”。
  • 为了解决这个问题,浏览器提供了异步任务队列 + 事件循环机制,让 JS 能“非阻塞”地处理异步逻辑。

✅ 核心思想:同步代码立即执行,异步代码稍后执行(由 Event Loop 调度)


二、Event Loop 的核心组成

Event Loop 依赖两个关键队列:

1. 宏任务队列(Macrotask Queue)

也叫 Task Queue,包含:

  • script(整体代码块)
  • setTimeout / setInterval
  • setImmediate(Node.js 独有)
  • I/O 操作(如 DOM 事件、AJAX 回调)
  • UI 渲染(部分浏览器将其视为宏任务)

2. 微任务队列(Microtask Queue)

优先级更高,包含:

  • Promise.then() / .catch() / .finally()
  • queueMicrotask()
  • MutationObserver(监听 DOM 变化)
  • process.nextTick()(Node.js,优先级甚至高于 Promise)

📌 关键规则
每执行完一个宏任务,就清空当前所有微任务,然后再进行下一轮宏任务。


三、Event Loop 执行流程(简化版)

1. 执行全局 script(第一个宏任务)

2. 遇到异步操作:
- 宏任务(如 setTimeout)→ 放入宏任务队列
- 微任务(如 Promise.then)→ 放入微任务队列

3. 当前宏任务执行完毕

4. **立即执行所有微任务**(直到微任务队列为空)

5. (可选)浏览器进行 UI 渲染(如 Layout/Paint)

6. 从宏任务队列取出下一个宏任务,重复上述过程

⚠️ 注意:微任务是在当前宏任务结束后、下一个宏任务开始前执行的,且会“冒泡式”执行(微任务中产生的新微任务也会被立即执行)。


四、经典示例解析

console.log('1');

setTimeout(() => console.log('2'), 0);

Promise.resolve().then(() => console.log('3'));

console.log('4');

执行过程:

  1. 全局 script(宏任务)开始执行:
    • 输出 '1'
    • setTimeout → 回调放入宏任务队列
    • Promise.then → 回调放入微任务队列
    • 输出 '4'
  2. 当前宏任务结束 → 执行所有微任务 → 输出 '3'
  3. 下一轮 Event Loop → 执行宏任务 → 输出 '2'

✅ 最终输出:

1
4
3
2

五、总结一句话

Event Loop 是浏览器协调同步代码、异步回调、渲染更新的调度机制:它先执行一个宏任务,再清空所有微任务,如此循环往复,确保页面响应性和异步逻辑的正确执行。

掌握 Event Loop,是理解前端性能优化、动画调度、框架原理(如 React/Vue 的更新机制)的基础。