Promise.resolve 返回 Promise 的执行顺序
分析 return Promise.resolve() 时的微任务执行机制
问题
以下代码的输出结果是什么?
Promise.resolve().then(() => {
console.log(0)
return Promise.resolve(4)
}).then((res) => {
console.log(res)
})
Promise.resolve().then(() => {
console.log(1)
}).then(() => {
console.log(2)
}).then(() => {
console.log(3)
}).then(() => {
console.log(5)
}).then(() =>{
console.log(6)
})
解答
输出结果是:0 1 2 3 5 6 4
原因分析
当 resolve 或 return 一个 Promise 对象时,Chrome 内部实现会产生额外的微任务。这与标准的 Promise/A+ 规范存在差异。
对比三种情况:
// 情况1:resolve 一个 Promise
new Promise(resolve => {
resolve(Promise.resolve(4))
})
.then((res) => {
console.log(res) // 4
})
// 情况2:return 一个 Promise
Promise.resolve().then(() => {
return Promise.resolve(4)
})
.then((res) => {
console.log(res) // 4
})
// 情况3:return 一个普通值
Promise.resolve().then(() => {
return 4
})
.then((res) => {
console.log(res) // 4
})
情况 1 和情况 2 虽然最终输出都是数字 4,但在执行过程中会比情况 3 多产生两个微任务。
执行机制
当 resolve 或 return 遇到 Promise 对象时:
- 先获取这个 Promise 的值(等待状态变为 fulfilled)
- 用微任务包装这个值
- 向外传递时再产生一个微任务
因此,return Promise.resolve(4) 可以理解为:
Promise.resolve().then(() => {
return 4
})
.then() // 额外的微任务1
.then() // 额外的微任务2
.then((res) => {
console.log(res)
})
题目转化
原题目可以转化为:
Promise.resolve().then(() => {
console.log(0)
return 4
})
.then()
.then()
.then((res) => {
console.log(res)
})
Promise.resolve().then(() => {
console.log(1)
}).then(() => {
console.log(2)
}).then(() => {
console.log(3)
}).then(() => {
console.log(5)
}).then(() =>{
console.log(6)
})
执行顺序:
- 第一轮微任务:输出 0 和 1
- 第二轮微任务:输出 2(第一个 Promise 链的空 then)
- 第三轮微任务:输出 3(第一个 Promise 链的空 then)
- 第四轮微任务:输出 5
- 第五轮微任务:输出 6
- 第六轮微任务:输出 4
特殊情况
嵌套多层 Promise.resolve() 不会产生额外微任务:
Promise.resolve().then(() => {
return Promise.resolve(Promise.resolve(Promise.resolve(4)))
})
.then(res => {
console.log(res) // 和 return Promise.resolve(4) 效果相同
})
但如果 Promise 链本身需要等待,则会累加微任务:
Promise.resolve().then(() => {
return new Promise(resolve => {
resolve(4)
})
.then(res => {
return 4.1
})
.then(res => {
return 4.2
})
})
.then(res => {
console.log(res) // 需要等待前面的 Promise 链执行完
})
关键点
return Promise.resolve(value)会比return value多产生两个微任务- 第一个微任务用于包装 Promise 的值,第二个微任务用于向外传递
- 嵌套的
Promise.resolve()不会产生额外微任务,因为状态立即确定 - 这是 Chrome 内部实现的特性,与标准 Promise/A+ 规范有差异
目录