所属板块:4. 异步编程与事件循环
记录日期:2026-03-xx
更新:遇到输出题或宏/微任务相关题时补充
1. JS 单线程与异步的本质
JavaScript 本身是单线程的(只有一个主调用栈 Call Stack)。
所有同步代码必须排队执行,但前端需要处理网络请求、定时器、DOM 事件等耗时操作——这些操作不能阻塞主线程。
解决方案:JS 引擎把耗时任务交给宿主环境(浏览器/Node.js),宿主环境在后台执行完后再把回调“通知”回来。这就是事件循环(Event Loop)的由来。
记住:JS 引擎只负责执行代码,异步调度由宿主环境 + Event Loop 共同完成。
2. 浏览器端的事件循环模型(核心运转流程)
整个流程可以拆成以下几个部分:
- 执行栈 (Call Stack):执行同步代码(包括 new Promise 的 executor)
- Web APIs:浏览器提供的异步线程(定时器、HTTP 请求、DOM 事件等)
- 任务队列:
- 宏任务队列(Macrotask Queue)
- 微任务队列(Microtask Queue)
Event Loop 的完整运转顺序(每次循环叫一个 Tick):
- 执行栈为空
- 先清空微任务队列(全部执行完)
- 执行一个宏任务
- 再次清空微任务队列
- (可选)渲染页面(UI 更新)
- 重复以上步骤
关键规则:一个宏任务之后,必须把当前所有微任务全部执行完,才能执行下一个宏任务。
3. 宏任务 vs 微任务(高频考点)
宏任务(Macrotask):
- script(整体代码)
- setTimeout / setInterval
- setImmediate(Node)
- I/O 操作
- UI 渲染
微任务(Microtask):
- Promise.then / catch / finally
- MutationObserver
- process.nextTick(Node,优先级极高)
经典执行顺序示例:
console.log("1");
setTimeout(() => console.log("2"), 0);
Promise.resolve().then(() => console.log("3"));
console.log("4");
输出顺序:1 → 4 → 3 → 2
原因:同步 → 微任务(Promise) → 宏任务(setTimeout)
4. Node.js 事件循环的差异(进阶了解)
Node.js 事件循环分为 6 个阶段(Timers → I/O callbacks → Idle/prepare → Poll → Check → Close callbacks)。
重要区别:
- Node 11 之前:微任务在每个阶段结束后执行
- Node 11 之后:与浏览器更接近(每个宏任务后清空微任务)
process.nextTick优先级高于所有微任务(几乎最先执行)
5. 小结 & 复习时的“调度视角”
- 遇到任何输出题,先画出:
- 执行栈 → 宏任务队列 → 微任务队列
- 严格遵守“一个宏任务后清空所有微任务”
- [4-1] 的事件循环机制是整个异步板块的底层基础,后面的 Promise、async/await 都会放到这个模型里执行
下一篇文章会进入 [4-2]:异步编程方案的演进(从回调地狱到 Promise 的状态流转与核心 API)。
返回总目录:戳这里