信息发布→ 登录 注册 退出

如何理解JavaScript中的微任务与宏任务_JavaScript任务队列如何影响代码执行

发布时间:2026-01-11

点击量:
JavaScript执行是单线程的,靠事件循环调度微任务(如Promise.then、queueMicrotask)和宏任务(如setTimeout、I/O),微任务在同步代码后立即清空执行,宏任务每次只执行一个且中间插入微任务检查。

JavaScript 的执行是单线程的,但靠任务队列机制实现异步行为。微任务(microtask)和宏任务(macrotask)不是语法层面的概念,而是事件循环(Event Loop)中对任务分类调度的实际规则——理解它们的关键,在于知道哪些操作会进入哪类队列、谁先执行、以及为什么 Promise.then 总比 setTimeout 先触发。

哪些操作产生微任务?

微任务在当前同步代码执行完后、下一轮宏任务开始前立即执行,且会清空整个微任务队列(即连续执行,不穿插渲染或 I/O)。常见来源包括:

  • Promise.prototype.then / .catch / .finally 回调(即使 Promise.resolve().then(...)
  • queueMicrotask() 显式加入的回调
  • MutationObserver 的回调
  • await 后续代码(本质是 Promise 微任务链的一部分)

注意:Promise 构造函数内的执行器(executor)是同步运行的,只有其内部的 resolve/reject 调用才会触发后续微任务。

哪些操作产生宏任务?

宏任务每次只执行一个,执行完后检查并清空全部微任务,再取下一个宏任务。典型来源有:

  • setTimeout / setInterval
  • setImmediate(Node.js 独有,非标准)
  • I/O 回调(如 fs.readFile 在 Node.js 中)
  • UI 渲染(浏览器中,虽不可直接调度,但属于宏任务周期的一部分)
  • postMessageMessageChannel 的消息处理

特别注意:setTimeout(fn, 0) 并不意味着“立刻执行”,它只是尽快把 fn 推入宏任务队列——实际执行要等当前宏任务 + 所有微任务完成之后。

执行顺序如何确定?看一个典型例子

下面这段代码能清晰体现两者的嵌套关系:

console.log(1);

setTimeout(() => console.log(2), 0);

Promise.resolve().then(() => console.log(3));

Promise.resolve().then(() => {
  console.log(4);
  setTimeout(() => console.log(5), 0);
});

console.log(6);

输出顺序是:163425。原因如下:

  • 同步代码先执行:16
  • 然后清空微任务队列:两个 Promise.then34),其中第二个还触发了一个新的 setTimeout(推入宏任务队列)
  • 接着取下一个宏任务:setTimeout2
  • 最后执行新推入的宏任务:5

关键点:微任务可以递归产生新微任务(比如 then 里再返回 Promise),它们都会被追加到当前微任务队列末尾,并在本轮全部执行完;而宏任务之间永远是串行的,中间必然插入微任务检查。

容易忽略的坑:async/await 与错误捕获

async 函数返回的是 Promise,await 后面的表达式一旦 resolve/reject,后续代码会被包装进微任务。这意味着:

  • 未被 try/catch 包裹的 await 错误,不会同步抛出,而是变成 rejected Promise,需靠 .catch 或顶层 unhandledrejection 捕获
  • 多个 await 连续写,它们之间是微任务衔接,不是同步栈;调试时断点可能“跳过”中间状态
  • await Promise.resolve() 会触发一次微任务调度,哪怕值已确定——这在性能敏感循环中可能成为隐性开销

真正难调试的,往往不是“谁先谁后”,而是微任务队列被意外延长(比如某个 then 里又创建了新 Promise 链),导致预期中的 DOM 更新延迟或状态不同步。

标签:# javascript  # java  # js  # node.js  # node  # 浏览器  # mac  #   # ai  # 为什么  
在线客服
服务热线

服务热线

4008888355

微信咨询
二维码
返回顶部
×二维码

截屏,微信识别二维码

打开微信

微信号已复制,请打开微信添加咨询详情!