宏任务是由宿主环境主动注入事件循环的任务,每次只执行一个,执行完后检查微任务队列;常见来源包括定时器、脚本加载、用户交互、I/O完成、消息通信及requestAnimationFrame等。

宏任务是 JavaScript 事件循环中由宿主环境(如浏览器或 Node.js)主动插入的任务,它构成一次完整的执行单元边界,每次只执行一个,并在执行完后检查微任务队列。
常见宏任务的产生方式
以下操作会直接向宏任务队列添加新任务:
-
定时器触发:调用
setTimeout或setInterval时,回调函数会在指定延迟后被推入宏任务队列(即使设为 0,也需等待当前宏任务结束)。 -
脚本加载与执行:
<script>标签内的全部同步代码,从解析到执行完成,整体被视为一个初始宏任务。 - 用户交互事件:点击、键盘输入、滚动等 DOM 事件的回调函数,在事件触发后被加入宏任务队列。
- I/O 操作完成:XMLHttpRequest 响应到达、fetch 请求 resolve、文件读取完成(Node.js)、WebSocket 收到消息等,其回调会被安排为宏任务。
-
消息通信 API:使用
window.postMessage发送消息后,目标窗口的message事件监听器会以宏任务形式执行;MessageChannel的port.onmessage同理。 -
渲染相关钩子:浏览器中的
requestAnimationFrame回调,在下一次重绘前被作为宏任务调度(注意:它不保证严格每帧一次,但属于宏任务范畴)。
宏任务的关键特征
它不是由 JavaScript 引擎“主动创建”的,而是由外部环境在特定时机“注入”到任务队列中的:
- 每个宏任务有明确起止——执行开始前清空调用栈,执行结束后才允许渲染(浏览器)或处理下一个宏任务。
- 宏任务之间天然隔离,一个出错不会中断另一个的排队,但会阻塞后续宏任务的执行(直到当前出错任务被处理完)。
- 宏任务内部可生成微任务(如 Promise.then),这些微任务不会立刻执行,而是排队等待当前宏任务彻底结束。
容易混淆的情况
有些操作看似异步,但不一定产生宏任务:
立即学习“Java免费学习笔记(深入)”;
-
Promise.resolve().then(...)产生的是微任务,不是宏任务。 -
queueMicrotask()明确用于添加微任务,与宏任务无关。 -
process.nextTick(仅 Node.js)属于微任务,且优先级高于 Promise 回调。 -
setImmediate(仅 Node.js)是宏任务,但优先级低于setTimeout(fn, 0),实际很少用。


















