宏任务在异步加载后执行,核心在于将回调函数推入宏任务队列(macrotask queue),等待当前调用栈清空且微任务队列排空后由事件循环调度。具体做法是调用 settimeout 或 setimmediate 等 api,它们会将指定的回调注册到宏任务队列中。当异步操作完成时,浏览器或 node.js 环境会触发这些回调,确保它们在同步代码和所有已排队的微任务之后执行。

setTimeout 如何安排宏任务
setTimeout 是最常用的安排宏任务的方法,它接受一个回调函数和一个延迟时间。调用该函数后,引擎会在指定时间后将回调放入宏任务队列。需要注意的是,实际执行时间可能晚于设定值,因为必须等待当前任务执行完毕且队列中没有更高优先级的任务。例如,设置 0 毫秒延迟并不能保证立即执行,而是将其排在下一个宏任务周期。

console.log('Start');
setTimeout(() => {
console.log('Timeout Callback');
}, 0);
Promise.resolve().then(() => {
console.log('Microtask');
});
console.log('End');运行上述代码,输出顺序为:Start、End、Microtask、Timeout Callback。这证明了即使延迟为 0,宏任务也必须在同步代码和微任务之后执行。
立即学习“Java免费学习笔记(深入)”;
setImmediate 与 process.nextTick 的区别
在 Node.js 环境中,setImmediate 用于在当前执行阶段结束后调度回调,属于宏任务。而 process.nextTick 虽然也是异步的,但它属于微任务范畴,优先级高于 Promise 的微任务。因此,在处理 I/O 回调时,使用 setImmediate 可以确保逻辑在 I/O 事件循环的下一阶段执行,避免阻塞后续 I/O 处理。

console.log('Start');
setImmediate(() => {
console.log('Immediate');
});
process.nextTick(() => {
console.log('NextTick');
});
Promise.resolve().then(() => {
console.log('Promise');
});
console.log('End');运行结果顺序为:Start、End、NextTick、Promise、Immediate。这表明 process.nextTick 和 Promise 微任务都在宏任务 setImmediate 之前执行。
宏任务队列满时的行为
当宏任务队列中积压了大量任务时,事件循环会逐个取出并执行。如果某个宏任务的执行时间过长,可能会阻塞后续的 UI 渲染或其他高优先级任务。因此,对于耗时较长的操作,应将其拆分为多个小任务,利用 setTimeout 或 requestAnimationFrame 分批执行,以保持界面的响应性。


















