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

Promise的finally为何会延迟后续then的执行?结合实例解析执行顺序逻辑

Promise的finally为何会延迟后续then的执行?结合实例解析执行顺序逻辑

我来给你掰扯清楚这个问题,核心要抓住两个关键点:直接挂载在原Promise上的回调顺序,以及finally的内部执行逻辑,咱们一步步拆解。

先搞懂第一个例子的执行流程

先看你第一个例子里,直接挂在value(也就是foo返回的Promise)上的回调有三个,按代码注册顺序是:

  1. 分支1的第一个then:a => a + 1
  2. 分支2的finally回调:() => 'finally'
  3. 分支3的第一个then:a => a + 2

当value变成resolved状态后,这三个回调会按注册顺序依次加入微任务队列,接下来微任务队列的执行是严格先进先出的,咱们一步步走:

  1. 执行分支1的第一个then:返回2,触发它后面的第二个then(输出then 1 2),这个第二个then的回调被加到微任务队列尾部。
  2. 执行finally回调:这里是关键!根据ES规范,finally本质上等价于用then包裹的逻辑:
    value.then(
      val => Promise.resolve('finally').then(() => val), // 咱们叫这个内部回调C1
      err => Promise.resolve('finally').then(() => { throw err; })
    )
    
    也就是说,执行完finally的回调后,还会生成一个新的微任务(就是上面的C1),这个微任务会被加到队列尾部。
  3. 执行分支3的第一个then:返回3,触发它后面的第二个then(输出then 2 3),这个回调也被加到队列尾部。

接下来按队列顺序执行:

  • 先执行分支1第二个then:输出then 1 2
  • 再执行分支3第二个then:输出then 2 3
  • 然后执行内部回调C1:这个回调返回原value的值1,触发finally后面的then(输出then after finally),把这个回调加到队列
  • 最后执行这个最终的then:输出then after finally

这就解释了为什么then after finally会在最后出现——因为finally多了一层内部微任务,被排在了分支3第二个then的后面。

再看第二个例子的差异

第二个例子里,分支1和分支3多了好几层then,这些后续的then都不是直接挂在value上的,而是挂在前面then返回的新Promise上。

执行到value变为resolved后,初始微任务队列还是[分支1第一个then, finally回调, 分支3第一个then],执行过程中:

  • 每执行一层then,都会把下一层then的回调加到队列尾部
  • 而finally产生的内部回调C1,会被夹在分支1、3的中间层then回调之间

比如执行到某一步时,队列顺序变成了[分支1第三个then, 分支3第三个then, 内部回调C1],所以会先执行分支1的then 3 undefined、分支3的then 4 undefined、分支1的then 5 undefined,才轮到内部回调C1,进而触发then after finally,之后再执行剩下的分支3、1的后续then。

核心结论

  1. 同Promise的直接回调按注册顺序排队:所有直接挂在value上的then/finally/catch,会按你写代码的顺序加入微任务队列。
  2. finally会多生成一个微任务:它的内部逻辑需要先执行回调,再通过一个额外的微任务来resolve原Promise的值,这是导致后续then延迟的关键。
  3. 微任务队列严格先进先出:新产生的微任务永远加到队尾,所以谁先被排进队列,谁就先执行。

备注:内容来源于stack exchange,提问作者b3rry

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 19:54:40