宏任务在当前同步代码和所有微任务执行完毕后才开始执行,典型来源包括整体script代码块、settimeout/setinterval、用户交互事件、网络请求回调及ui渲染等。

要理解宏任务的触发时机,关键不是记住哪些是宏任务,而是看清事件循环中“谁先排队、谁后执行”的实际节奏。宏任务不是一出现就立刻运行,它必须等到当前所有同步代码和微任务都处理完,才轮到它被取出执行。
宏任务的典型来源有哪些
这些操作会把回调函数注册进宏任务队列,但不会马上执行:
- 整体 script 代码块:页面加载时整个 `<script>` 内容本身就是第一个宏任务</script>
- setTimeout / setInterval:即使设为 0 毫秒,也只是“尽快加入宏任务队列”,不等于立即执行
- 用户交互事件:比如 click、scroll、input 等,事件回调进入宏任务队列
- 网络请求完成回调:XMLHttpRequest 的 onload、fetch 的 then(注意:then 本身是微任务,但 fetch 的底层响应处理属于宏任务阶段)
- I/O 操作与 UI 渲染:浏览器在每轮事件循环末尾可能插入渲染任务,也归为宏任务
宏任务何时真正开始执行
事件循环每次只取一个宏任务来执行,流程固定:
- 先运行当前宏任务里的所有同步代码(比如 console.log、函数调用)
- 过程中遇到 Promise.then、MutationObserver 等,会把它们加入微任务队列
- 当前宏任务执行完毕,调用栈清空 → 立即执行全部微任务(逐个清空,不中断)
- 微任务队列为空 → 浏览器可能进行一次 UI 渲染(非强制)
- 然后才从宏任务队列中取出下一个宏任务,重复上述过程
一个典型例子帮你锁定时机
看这段代码:
console.log('A');setTimeout(() => console.log('B'), 0);
Promise.resolve().then(() => console.log('C'));
console.log('D');
输出顺序是 A → D → C → B。这里 B 是 setTimeout 回调,它虽早被注册,但必须等同步代码(A、D)和微任务(C)全部走完,才作为下一轮事件循环的第一个宏任务被执行。
如何判断某个操作是否触发宏任务
问自己三个问题:
- 这个操作是否由宿主环境(浏览器/Node)发起,而非 JS 引擎直接调度?→ 是,大概率是宏任务
- 它的回调是否需要等待外部条件(如时间到达、用户点击、网络响应)?→ 是,说明它被推入宏任务队列等待
- 它是否在当前脚本执行完之后、且所有 Promise.then 都跑完才发生?→ 是,那就符合宏任务的执行位置










