关于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
接下来一步步走事件循环的执行流程:
同步代码执行阶段:
- 执行第一个Promise构造函数:同步打印
1,调用resolve()后,这个Promise变为fulfilled状态,它的第一个then回调(回调A)被加入微任务队列。 - 执行第二个Promise构造函数:同步打印
a,调用resolve()后,这个Promise变为fulfilled状态,它的第一个then回调(回调B)被加入微任务队列。
此时同步代码执行完毕,微任务队列内容:[回调A, 回调B]
- 执行第一个Promise构造函数:同步打印
微任务队列处理阶段:
- 取出队列第一个任务回调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,微任务队列清空。
- 同步打印
- 取出队列第一个任务回调A执行:
这样整个输出顺序就是: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
相关产品推荐
相关产品推荐

