javascript如何实现宏任务_有哪些例子

宏任务是事件循环中每次迭代执行一个的任务,优先级低于微任务,常见类型包括setTimeout、setInterval、setImmediate(Node.js)、I/O回调、UI渲染、postMessage、MessageChannel及script初始执行;其执行顺序为:执行一个宏任务→清空所有微任务→渲染(浏览器)→进入下一宏任务。

JavaScript 中的宏任务(Macrotask)是事件循环中的一类任务,它们在每次事件循环的迭代中执行一个,且优先级低于微任务(Microtask)。宏任务的主要特点是:每个宏任务执行完后,会清空当前所有微任务队列,再进入下一个宏任务。

常见的宏任务有哪些

以下是最典型的宏任务来源,它们都会被推入宏任务队列(macrotask queue),等待主线程空闲时依次执行:

  • setTimeoutsetInterval 的回调函数
  • setImmediate(仅 Node.js 环境支持)
  • I/O 操作完成后的回调(如文件读取、网络请求的 callback,Node.js 中)
  • UI 渲染任务(浏览器环境,虽不可直接调用,但属于宏任务范畴)
  • postMessageMessageChannel 的消息处理回调
  • script 标签的初始执行(整个脚本本身就是一个宏任务)

宏任务和微任务的执行顺序

理解宏任务的关键在于它和微任务的协作关系。一次事件循环包含:

  • 执行一个宏任务(如 setTimeout 回调)
  • 立即执行所有已排队的微任务(如 Promise.then、queueMicrotask)
  • 渲染(浏览器环境,若需要)
  • 进入下一个宏任务

例如:

console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
// 输出顺序:1 → 4 → 3 → 2

这里 setTimeout 是宏任务,排在下一轮;而 Promise.then 是微任务,插在当前宏任务末尾、下个宏任务前执行。

如何手动触发一个宏任务

没有直接 API 叫 “createMacrotask”,但你可以用标准方式“间接创建”:

  • 使用 setTimeout(fn, 0)setTimeout(fn, 1)(最常用)
  • 使用 setImmediate(fn)(Node.js)
  • MessageChannel 发送空消息(轻量、无延迟,但仍是宏任务):
const channel = new MessageChannel();
channel.port2.onmessage = () => console.log('宏任务执行了');
channel.port1.postMessage(0);

注意:虽然 MessageChannel 延迟极低,但它仍属于宏任务,且会在当前微任务之后、下一个宏任务阶段执行。

为什么 setTimeout(0) 不是立刻执行

因为 JavaScript 的事件循环机制规定:即使延迟设为 0,setTimeout 回调也必须等到当前宏任务 + 所有微任务执行完毕后,才进入下一轮宏任务队列。它只是“尽快安排”,不是“立即插入当前执行栈”。

这也解释了为什么它比 Promise.then 慢——后者属于微任务,抢占更靠前的时机。

基本上就这些。宏任务是理解 JS 异步行为的基石,掌握它能帮你理清异步代码的真实执行节奏。