宏任务与微任务
在 JavaScript 的事件循环机制中,宏任务(MacroTask) 和 微任务(MicroTask) 是两种不同优先级的异步任务类型,它们的执行顺序直接影响代码的运行逻辑。以下是它们的核心区别和关键细节:
一、核心区别
| 特性 | 宏任务(MacroTask) | 微任务(MicroTask) |
|---|---|---|
| 定义 | 由宿主环境(如浏览器、Node.js)发起的任务 | 由 JavaScript 自身发起的任务 |
| 执行顺序 | 在事件循环的每一轮中执行一个宏任务 | 在当前宏任务执行后、下一个宏任务前全部执行 |
| 常见示例 | setTimeout, setInterval, I/O 操作, UI 渲染 |
Promise.then/catch/finally, process.nextTick(Node.js), MutationObserver |
| 优先级 | 低 | 高 |
二、事件循环流程
- 执行一个宏任务(如主代码块、
setTimeout回调)。 - 执行所有微任务:清空微任务队列。
- 渲染更新(浏览器环境下可能触发 UI 渲染)。
- 进入下一轮事件循环,执行下一个宏任务。
三、代码示例分析
console.log("Script start"); // 宏任务(主线程)
setTimeout(() => {
console.log("setTimeout"); // 宏任务(下一轮事件循环)
}, 0);
Promise.resolve()
.then(() => {
console.log("Promise 1"); // 微任务
})
.then(() => {
console.log("Promise 2"); // 微任务
});
console.log("Script end"); // 宏任务(主线程)
输出顺序:
Script start → Script end → Promise 1 → Promise 2 → setTimeout
四、关键细节
-
微任务优先级更高
微任务会在当前宏任务结束后立即执行,而宏任务需等待下一轮事件循环。
例如:在同一个事件循环中,即使宏任务(如setTimeout)的回调已就绪,也必须等待所有微任务执行完毕。 -
微任务会“插队”
如果在微任务中触发新的微任务,这些新微任务会继续加入当前队列,直到队列清空。这可能导致宏任务被长时间阻塞。 -
应用场景
- 宏任务:适合不紧急的任务(如延迟操作、批量渲染)。
- 微任务:适合需要高优先级响应的任务(如 Promise 链式调用、DOM 更新后的回调)。
五、常见问题
为什么 Promise 比 setTimeout 先执行?
Promise回调属于微任务,会在当前宏任务结束后立即执行。setTimeout是宏任务,必须等待所有微任务执行完毕,再进入下一轮事件循环。
如何避免微任务阻塞?
避免在微任务中编写耗时逻辑,否则会延迟后续宏任务执行,导致页面卡顿。
六、总结
- 宏任务是 JavaScript 异步的“大颗粒”任务,按事件循环的轮次执行。
- 微任务是“细颗粒”任务,在当前宏任务结束后立即执行,确保高优先级逻辑及时处理。
- 理解两者的执行顺序,是避免异步代码 Bug 的关键(如竞态条件、渲染顺序问题)。

浙公网安备 33010602011771号