为何async函数返回Promise首次打印为pending,其余为fulfilled?
问题原因解析
这个现象和你加不加await没有关系,核心是async函数的返回值包装规则+JS微任务调度机制,具体拆解:
普通函数返回Promise的状态逻辑
testFunc2和testFunc3是普通箭头函数,返回Promise的逻辑非常直接:
- Promise构造器传入的executor函数是同步执行的,你写在里面的
resolve()会在函数调用的同步阶段立刻触发 - 所以当你在同步代码行打印这两个函数的返回值时,Promise已经被同步标记为
fulfilled状态,自然显示<fulfilled>: undefined
async函数返回Promise的特殊逻辑
被async修饰的testFunc,返回值规则和普通函数有本质区别:
- 不管async函数内部return的是什么值——哪怕是一个已经resolve的Promise实例——函数被调用时,都会先同步返回一个全新的、处于pending状态的外层Promise
- 内部return的值会被丢进微任务队列做状态对齐:必须等当前所有同步代码执行完,才会跑这个微任务,把外层Promise的状态改成和内部return的Promise一致
- 你在同步阶段打印
testFunc()的返回值时,状态对齐的微任务还没轮到执行,所以看到的是pending状态。这个Promise不会一直卡pending,只是你打印的时机太早,没等到它状态流转完成。
输出顺序的逻辑
你看到的回调执行顺序,完全是微任务队列先进先出调度的结果:
- 同步执行阶段,
testFunc2和testFunc3返回的Promise已经同步resolve,所以它们的第一个then回调(打印1、打印4)会直接加入微任务队列;而testFunc的外层Promise还在等状态对齐的微任务,它的第一个then回调(打印Hello)要等状态对齐完成才会入队,自然比前两个的第一个回调晚执行 - 后续链式调用的then回调,都会等上一个回调执行完才会依次入队,最终就得到了你贴出来的输出顺序
验证方式
你只要把打印testFunc()返回值的逻辑放到异步任务里,等过了第一个微任务周期再打,就能看到它最终是fulfilled状态:
// 放到微任务中打印 Promise.resolve().then(() => console.log(testFunc())) // 放到宏任务中打印 setTimeout(() => console.log(testFunc()), 0)
这两处打印的结果都会是Promise {<fulfilled>: undefined}。
内容的提问来源于stack exchange,提问作者Georgy27OP
相关产品推荐
相关产品推荐

