You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript事件循环中Promise.then与queueMicrotask执行顺序问题求教

JavaScript事件循环微任务执行规则说明

首先明确3个核心底层规则:

  • 所有微任务(Promise.then回调、queueMicrotask回调等)优先级完全相同,微任务队列遵循先进先出的执行顺序
  • 同步代码执行栈清空后,会持续执行微任务队列中的所有任务直到队列为空,才会处理宏任务;单个微任务执行过程中新增的微任务,会追加到微任务队列末尾,在本次微任务清空流程内执行
  • Promise的then回调会在其所属Promise状态变为resolved/rejected后立刻加入微任务队列;链式调用的then回调,会等前一个then的回调执行完毕、返回的Promise状态确定后,才会被加入队列

第一个代码执行顺序拆解

你给出的第一段代码执行步骤完全符合上述规则:

Promise.resolve()
  .then(() => {
      Promise.resolve().then(() => {
          Promise.resolve().then(() => {
              Promise.resolve().then(() => {
                  console.log('first mega inner then')
              })
              console.log('first very inner then')
          })
          console.log('first inner then')
      })
      console.log('first then')
  })
  .then(() => {
      Promise.resolve().then(() => {
          Promise.resolve().then(() => {
              console.log('second very inner then')
          })
          console.log('second inner then')
      })
      console.log('second then')
  })

具体执行流程:

  1. 同步代码阶段:最外层Promise.resolve()状态已完成,将第一个then的回调记为T1加入微任务队列。外层第二个then的回调记为T2,因前一个then返回的Promise还未resolve,暂不加入队列。此时微任务队列:[T1]
  2. 同步栈清空,开始执行微任务队列:
    • 执行T1:内部创建的Promise的then回调T1_inner1加入微任务队列,打印first then。T1执行完毕,前一个then返回的Promise变为resolved,将T2追加到微任务队列末尾。此时微任务队列:[T1_inner1, T2]
    • 执行T1_inner1:内部创建的Promise的then回调T1_inner2加入队列,打印first inner then。此时微任务队列:[T2, T1_inner2]
    • 执行T2:内部创建的Promise的then回调T2_inner1加入队列,打印second then。此时微任务队列:[T1_inner2, T2_inner1]
    • 执行T1_inner2:内部创建的Promise的then回调T1_inner3加入队列,打印first very inner then。此时微任务队列:[T2_inner1, T1_inner3]
    • 执行T2_inner1:内部创建的Promise的then回调T2_inner2加入队列,打印second inner then。此时微任务队列:[T1_inner3, T2_inner2]
    • 执行T1_inner3:打印first mega inner then。此时微任务队列:[T2_inner2]
    • 执行T2_inner2:打印second very inner then

你之前的预期错误核心是忽略了:第一个外层then回调执行完毕后,外层第二个then的回调会立刻被加入微任务队列,排在T1_inner2之前,所以会先执行T2输出second then,而非等所有内层嵌套的Promise回调执行完再处理外层链式的then。


新增queueMicrotask后的执行逻辑

你新增的queueMicrotask是在同步代码阶段执行的,不是在某个then回调内部执行的,所以执行步骤会发生变化:

  1. 同步代码阶段:T1加入微任务队列后,立刻执行queueMicrotask(() => console.log('microtask')),将这个微任务记为QM追加到队列末尾。此时微任务队列:[T1, QM],T2还是暂未加入队列。
  2. 同步栈清空,开始执行微任务队列:
    • 执行T1:T1_inner1加入队列,打印first then,T1执行完毕,将T2追加到队列末尾。此时微任务队列:[QM, T1_inner1, T2]
    • 执行QM:打印microtask。此时微任务队列:[T1_inner1, T2]
    • 后续执行逻辑和第一个场景完全一致,所以最终输出顺序和你看到的结果相同。

内容的提问来源于stack exchange,提问作者Rasul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 08:39:01