事件循环严格遵循“宏→微(全部)→宏→微(全部)”节奏:每执行一个宏任务后,立即清空当前所有微任务队列,再取下一个宏任务;宏任务包括script、settimeout等,微任务包括promise.then、queuemicrotask等。

JavaScript 的事件循环中,宏任务与微任务的交替执行遵循明确的规则:每次执行完一个宏任务后,会清空当前所有微任务队列,再取下一个宏任务。这不是“交替穿插”,而是“宏→微(全部)→宏→微(全部)”的严格节奏。
宏任务与微任务的典型来源
理解执行顺序的前提是分清哪些是宏任务、哪些是微任务:
- 宏任务:script 脚本整体、setTimeout、setInterval、setImmediate(Node.js)、I/O、UI 渲染、postMessage
- 微任务:Promise.then/catch/finally、MutationObserver 回调、queueMicrotask()、Promise 构造函数中的同步代码(注意:它本身不入队,但 then 会)
一次完整的事件循环步骤
浏览器或 Node.js 每轮事件循环按以下顺序推进:
- 从宏任务队列取出**最早进入**的一个任务(如 setTimeout 回调),执行它
- 执行过程中若产生微任务(如 new Promise(() => {}).then(...)),它们被加入**当前微任务队列**(不是下次)
- 该宏任务执行完毕后,立即、**连续执行完当前微任务队列中的所有任务**(先进先出),期间新产生的微任务也会追加到队尾并被执行
- 微任务队列清空后,可能触发 UI 渲染(浏览器环境)
- 回到第 1 步,取下一个宏任务
用代码直观看执行顺序
下面这段代码能清晰体现宏微任务调度逻辑:
console.log('1'); // 同步脚本(宏任务)
<p>setTimeout(() => console.log('2'), 0); // 宏任务(下一轮)</p><p>Promise.resolve().then(() => console.log('3')); // 微任务(本轮)</p><p>console.log('4'); // 同步脚本(宏任务)</p><p>// 输出顺序:1 → 4 → 3 → 2</p>解释:
- '1' 和 '4' 是初始 script 宏任务的同步部分;
- Promise.then 在 script 执行中注册,成为本轮微任务;
- setTimeout 回调被推入下一轮宏任务队列;
- script 宏任务结束后,立即执行微任务 '3';
- 然后才开始下一轮,执行 '2'。
常见误区与注意事项
- 微任务不会被宏任务“打断”:一旦开始执行微任务队列,就会全部跑完,中间不会插入任何宏任务(包括更高优先级的 setTimeout(0))
- Promise 构造器内是同步的:new Promise(r => { console.log('sync'); r(); }) 中的 console.log 会立刻输出,不属于微任务
- queueMicrotask 是纯微任务入口:它和 Promise.then 效果一致,但更语义明确,且不涉及 Promise 状态管理开销
- 多个 Promise 链会累积微任务:p.then(a).then(b).then(c) 会依次入队三个微任务,按序执行
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











