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

关于Promise.then与async函数结合执行顺序的技术问询

解惑Promise.then与async函数的执行顺序

嘿,我来帮你拆解这个问题,搞懂执行顺序的核心逻辑,还有你提到的几个疑问~

一、为什么数字3会插在d和e之间?

先把代码里的回调都标记一下,方便梳理执行流程:

// 第一个Promise链
new Promise((resolve) => { console.log(1); resolve(); })
.then(async () => { console.log(2); }) // 回调A
.then(async () => { console.log(3); }); // 回调C

// 第二个Promise链
new Promise((resolve) => { console.log("a"); resolve(); })
.then(() => { console.log("b"); }) // 回调B
.then(() => { console.log("c"); }) // 回调D
.then(() => { console.log("d"); }) // 回调E
.then(() => { console.log("e"); }); // 回调F

接下来一步步走事件循环的执行流程:

  1. 同步代码执行阶段:

    • 执行第一个Promise构造函数:同步打印1,调用resolve()后,这个Promise变为fulfilled状态,它的第一个then回调(回调A)被加入微任务队列。
    • 执行第二个Promise构造函数:同步打印a,调用resolve()后,这个Promise变为fulfilled状态,它的第一个then回调(回调B)被加入微任务队列。
      此时同步代码执行完毕,微任务队列内容:[回调A, 回调B]
  2. 微任务队列处理阶段:

    • 取出队列第一个任务回调A执行:
      • 同步打印2,这个async函数执行完毕后,会返回一个resolved状态的Promise,它的then回调(也就是回调C)会被加入微任务队列末尾。此时队列内容变为:[回调B, 回调C]
    • 取出队列下一个任务回调B执行:
      • 同步打印b,函数返回undefined,等价于return Promise.resolve(undefined),所以它的then回调(回调D)被加入队列末尾。队列内容变为:[回调C, 回调D]
    • 取出队列下一个任务回调D执行:
      • 同步打印c,返回undefined,对应的then回调(回调E)加入队列末尾。队列内容变为:[回调C, 回调E]
    • 取出队列下一个任务回调E执行:
      • 同步打印d,返回undefined,对应的then回调(回调F)加入队列末尾。队列内容变为:[回调C, 回调F]
    • 取出队列下一个任务回调C执行:
      • 同步打印3,async函数执行完毕,返回resolved的Promise,没有后续then回调,队列内容变为:[回调F]
    • 取出队列最后一个任务回调F执行:
      • 同步打印e,微任务队列清空。

这样整个输出顺序就是:1, a, 2, b, c, d, 3, e,完全符合你看到的结果~ 核心是微任务队列先进先出的规则,回调C在回调A执行后被加入队列,排在回调B后面,之后每次新的回调都被加到队列末尾,所以回调C会在回调E执行完、回调F执行前被处理,也就导致3出现在d和e之间。

二、关于“每经过三个Promise.then就插入任务队列”的误解

你观察到的现象其实是微任务队列排队顺序的巧合,不是固定的“三个then”规则。在这个例子里,回调C排在了回调B、D、E的后面,是因为:

  • 回调C是在回调A执行后被加入队列,此时队列里已经有回调B;
  • 回调B、D、E执行时,每次都把下一个回调加到队列末尾,所以回调C一直被挤在这些新回调的前面,直到E执行完添加F后,才轮到C执行。
    如果调整第二个Promise链的then数量,比如改成2个then,那3就会插在c之后、d之前,你可以试试验证~

三、async函数作为Promise回调是否等价于返回Promise.resolve?

不完全等价,但在没有await、没有抛出错误的场景下,效果是一致的:

  • 当async函数内部没有await,且正常执行完毕(没有抛出错误),它会返回一个resolved状态的Promise,值为函数的返回值(如果没有return就是undefined),这和普通函数() => { ...; return Promise.resolve(返回值); }的效果完全一样。
  • 但如果async函数内部有await,或者抛出错误,就有区别了:
    • 遇到await时,async函数返回的Promise会等待await后的Promise完成,才会变为resolved状态;
    • 如果async函数内部抛出错误,返回的Promise会变为rejected状态,而普通函数抛出错误会直接触发同步错误(除非被try/catch捕获)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 21:24:09