async函数主动返回Promise的行为解析及与普通函数的差异
async函数返回Promise时的执行逻辑差异解析
核心差异原因
你遇到的问题本质是async函数对返回值的特殊包装规则,导致微任务队列的执行顺序发生了变化。
1. async函数的返回值处理规则
当你给函数加上async关键字后,JS会自动对函数的返回值做一层处理:
- 如果返回的是普通值,会直接包装成一个resolved状态的Promise;
- 如果返回的本身就是一个Promise对象,JS会把这个Promise再包裹进一个新的Promise中——换句话说,async函数的返回Promise会等待你内部返回的Promise完成后,才会跟着变更状态。这个等待过程会额外生成一个微任务。
简单来说:async function async2() { return p } 等价于 function async2() { return Promise.resolve(p) },而Promise.resolve(p)当p是Promise时,会触发一个微任务来等待p的状态完成。
2. 两种代码的执行流程对比
场景一:移除async关键字的情况
函数直接返回一个已resolved的Promise(因为new Promise((resolve) => resolve('hello'))在创建时就立即执行了resolve)。此时:
async2().then(...)的回调会被直接加入当前微任务队列的尾部;- 同时
Promise.resolve().then(...)的第一个回调也加入微任务队列。
微任务队列的执行顺序是:
- 执行
async2的then回调,打印hello和async1; - 执行
Promise.resolve的第一个then回调,打印1; - 接着执行后续链式then回调,依次打印
2、3。
所以最终输出顺序是hello→async1→1→2→3。
场景二:保留async关键字的情况
async函数返回已resolved的Promise时,会额外生成一个微任务来完成包装:
- 调用
async2()后,内部返回的Promise已经resolved,但async函数的返回Promise需要等待这个内部Promise的结果,这个等待过程会先产生一个微任务; - 同步代码执行完后,先处理
Promise.resolve().then(...)的第一个回调(打印1),执行完后第二个then回调(打印2)加入队列; - 处理打印
2的回调后,第三个then回调(打印3)加入队列; - 此时,async函数包装返回Promise的微任务执行完毕,
async2()的返回Promise变为resolved,它的then回调(打印hello、async1)被加入队列; - 先执行这个回调,再执行剩下的打印
3的回调。
所以最终输出顺序是1→2→hello→async1→3。
总结
- 不带async的函数直接返回Promise时,then回调会被立即加入当前微任务队列,执行优先级更高;
- 带async的函数返回Promise时,会多一层微任务包装,导致then回调的执行被推迟到下一轮微任务,从而改变了整体的输出顺序。
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

