You need to enable JavaScript to run this app. 为什么async函数返回已决议的Promise时不会立刻完成兑现?
优惠活动
大模型
产品
解决方案
定价
更多

为什么async函数返回已决议的Promise时不会立刻完成兑现?

核心原理说明

你遇到的现象完全符合ECMAScript规范对async函数和Promise决议流程的定义,核心要先纠正两个常见认知误区:

  1. async函数永远返回自身创建的外层Promise,不会直接返回你内部return的Promise
    MDN的描述只说明了普通返回值的情况,当你返回的是thenable(包括Promise实例)时,外层Promise不会直接复用你返回的实例,而是会启动「Promise解包流程」,等待你返回的Promise决议后,再用它的结果决议外层的Promise,这个解包过程需要多轮微任务调度。
  2. 用一个Promise作为参数调用另一个Promise的resolve方法时,需要2轮微任务才能完成决议
    这是ES规范明确要求的逻辑:当执行resolve(p),且p是一个Promise实例时,引擎会先注册一个微任务调用p.then(),拿到p的结果后,还要再注册一个微任务才能完成外层Promise的决议。

第一个示例的差异解释

async function f1(){
    return 100;
}
async function f2(){
    return Promise.resolve(100);
}
console.log(f1()); // Promise {<fulfilled>: 100}
console.log(f2()); // Promise <pending>
  • f1返回普通值100,不需要解包,外层Promise直接被决议为100,所以同步打印时已经是fulfilled状态。
  • f2返回已经决议的Promise,外层Promise需要启动解包流程,所以同步打印时还处于pending状态,解包完成后才会变成fulfilled。
    你看到展开pending的Promise能看到[[PromiseResult]]是100,是浏览器控制台的实现特性:你展开时Promise已经完成解包,控制台会展示最新状态,不是打印时就已经决议完成。

测试代码的执行流程拆解

我们一步步分析你写的测试代码的完整执行顺序:

let o = new Promise(function (r){
    r(100)
});
o.then(x => console.log(p))
.then(x => console.log(p))
.then(x => console.log(p))
async function f(){
    return new Promise(function (r){
        r(100)
    })
}
let p = f();

同步代码执行阶段

  1. 实例化Promise o,立刻执行resolve(100),o变成fulfilled状态。
  2. 给o绑定第一个then回调,因为o已经fulfilled,第一个回调被推入微任务队列,此时微任务队列:[第一个then回调]
  3. 给第一个then返回的Promise绑定第二个then回调,此时第一个then的Promise还处于pending,第二个回调暂不进入队列。
  4. 给第二个then返回的Promise绑定第三个then回调,同样暂不进入队列。
  5. 执行f():
    • 函数内部创建已经resolve(100)的Promise innerP。
    • async函数生成外层Promise p,初始状态为pending。
    • 启动解包流程:调用p的resolve方法传入innerP,按照规范生成第一个解包微任务unpack1推入队列,此时微任务队列:[第一个then回调, unpack1]
  6. 同步代码执行完毕,开始逐批清空微任务队列。

微任务第一轮处理

  • 执行第一个then回调:打印p,此时p还没解包完成,输出pending。回调返回undefined,第一个then的Promise被resolve,将第二个then回调推入队列,此时微任务队列:[unpack1, 第二个then回调]
  • 执行unpack1:调用innerP.then(),因为innerP已经fulfilled,将第二个解包微任务unpack2推入队列,此时微任务队列:[第二个then回调, unpack2]

微任务第二轮处理

  • 执行第二个then回调:打印p,unpack2还没执行,p还是pending,输出pending。回调返回undefined,第二个then的Promise被resolve,将第三个then回调推入队列,此时微任务队列:[unpack2, 第三个then回调]
  • 执行unpack2:用innerP的结果100决议p,p变成fulfilled状态,值为100。

微任务第三轮处理

  • 执行第三个then回调:打印p,此时p已经决议完成,输出Promise {<fulfilled>: 100}

这就完全解释了你观察到的「第三个then才打印出fulfilled状态」的现象。


关于await的补充说明

如果async函数内部有await关键字,逻辑完全一致:await会暂停函数执行,等后面的Promise决议后恢复执行,最终函数的返回值还是会走相同的解包流程,决议async函数自动生成的外层Promise。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.18 04:06:03