宏任务在事件循环中按fifo顺序执行,需等待执行栈清空及微任务队列清空后才被取出;常见来源包括settimeout、setinterval、setimmediate(node.js)、i/o回调、ui渲染和messagechannel的onmessage回调。

JavaScript 的宏任务(Macrotask)在产生后,会根据事件循环机制被排入对应的宏任务队列,等待当前执行栈清空、微任务队列执行完毕后,由事件循环依次取出执行。
宏任务的常见来源
以下操作会创建新的宏任务,并将其加入宏任务队列:
- setTimeout 和 setInterval 的回调函数(即使延时为 0,也属于宏任务)
- setImmediate(仅 Node.js 环境支持)
- I/O 操作完成后的回调(如文件读取、网络请求响应等)
- UI 渲染(浏览器中一次渲染帧可视为一个宏任务边界)
-
MessageChannel 的
port.onmessage回调(注意:虽然它常被用来模拟微任务,但实际是宏任务)
宏任务入队的时机与规则
宏任务不是“立刻执行”,而是在满足条件时被调度器插入宏任务队列:
- 定时器到期时(如 setTimeout 到达设定延迟),回调被加入宏任务队列(不是立即执行)
- 异步操作(如 fetch 响应、readFile 完成)结束后,其 then/catch 回调中的 非 Promise 链部分(即外层回调)属于宏任务
- 宏任务队列是先进先出(FIFO)结构,但不同来源可能有独立子队列(如 Chrome 中 setTimeout 和 I/O 回调可能分属不同队列,但对外表现为统一调度顺序)
- 宏任务只有在当前执行栈为空、且所有微任务执行完后,才会从队列头部取出一个执行
和微任务的关键区别
宏任务与微任务(如 Promise.then、queueMicrotask)共存于事件循环,但优先级不同:
- 每次宏任务执行完毕后,会清空整个微任务队列(直到无新微任务加入)
- 宏任务之间必然穿插一次完整的微任务清空过程
- 微任务不会被新的宏任务“插队”;而新的宏任务只能等到当前宏任务 + 所有微任务都结束后才执行
简单验证方式
可通过嵌套 setTimeout 和 Promise 来观察执行顺序:
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
// 输出:1 → 4 → 3 → 2
说明:同步代码(1、4)先执行;接着执行微任务(3);最后轮到宏任务队列里的 setTimeout 回调(2)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











