下面这段代码的执行结果是:
脚本启动 承诺1 承诺2 脚本结束 承诺3 种族:A
Chrome 版本 131.0.6778.26 和节点环境 22.4 都给出相同的结果
为什么执行完promise3后会执行“'race': A”,我的理解是Promise.race也是一个先放入微任务栈的微任务,所以应该先执行,但是结果不是这样的,这个问题困扰我很久了。 我希望能够给出一些官方的解释,如果您能解答我的困惑,我将非常感激!
console.log('script start')
const promise1 = new Promise((resolve, reject) => {
console.log('promise1')
resolve("A")
})
const promise2 = new Promise((resolve, reject) => {
console.log('promise2')
resolve("B")
})
const p = Promise.race([promise1, promise2])
.then((value) => {
console.log('race:', value)
}).catch((error) => {
console.log(error)
})
Promise.resolve().then(()=> {
console.log('promise3')
})
console.log('script end')
我希望得到一些官方的解释,最好深入到源代码级别!
区别在于添加微任务的时间。
Promise.resolve().then(...)
当 JS 调用此函数时,它会在
already已完成的 Promise 上调用
.then()
,因此它可以在执行此行时立即将此处理程序添加到微任务队列中(spec link),因此回调将执行为下一个微刻度的一部分。
Promise.race([...]).then(...)
Promise.race()
不会返回立即履行的承诺。相反,它需要处理您传递给它的承诺的履行,然后根据此结果自行解决,然后最终调用您的 .then()
处理程序。您可以考虑种族在内部为您的案例执行此操作(规范链接):
race(iterable) {
const raceResolvers = Promise.withResolvers();
for (const promise of iterable) {
const nextPromise = Promise.resolve(promise);
nextPromise.then(raceResolvers.resolve, raceResolvers.reject);
}
return raceResolvers.promise;
}
在内部,
Promise.race()
返回的承诺由附加有promise1
回调的promise2
/.then()
解决,这意味着现在您有两个步骤:
.then()
在内部添加的 .race()
处理程序作为微任务排队.race()
返回的承诺将得到解决,然后导致您的.then((value) => { console.log('race:', value) })
处理程序被添加到微任务队列在上面的步骤 1 和 2 之间,
Promise.resolve().then(()=> {console.log('promise3')});
能够将其处理程序添加到微任务队列中,这就是为什么您会看到 promise3
首先出现在 race:
日志之前。