事件循环中promise.race()的顺序

问题描述 投票:0回答:1

下面这段代码的执行结果是:

脚本启动 承诺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')

我希望得到一些官方的解释,最好深入到源代码级别!

javascript node.js promise event-loop
1个回答
0
投票

区别在于添加微任务的时间。

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()
解决,这意味着现在您有两个步骤:

  1. 首先,由
    .then()
    在内部添加的
    .race()
    处理程序作为微任务排队
  2. 一旦这些任务运行(即:主脚本执行完毕并且调用堆栈为空),
    .race()
    返回的承诺将得到解决,然后导致您的
    .then((value) => { console.log('race:', value) })
    处理程序被添加到微任务队列

在上面的步骤 1 和 2 之间,

Promise.resolve().then(()=> {console.log('promise3')});
能够将其处理程序添加到微任务队列中,这就是为什么您会看到
promise3
首先出现在
race: 
日志之前。

© www.soinside.com 2019 - 2024. All rights reserved.