并发承诺的顺序如何在异步函数中工作?

How does the order of concurrent promises work in an asynchronous function?

我注意到 MDN:

中的并发承诺示例
async function foo() {
   const p1 = new Promise((resolve) => setTimeout(() => resolve('1'), 1000))
   const p2 = new Promise((_,reject) => setTimeout(() => reject('2'), 500))
   const results = [await p1, await p2];
}
foo().catch(() => {}) // Attempt to swallow all errors...

MDN 声明:

in the following code an unhandled promise rejection error will be thrown, even if a .catch handler has been configured further along the promise chain. This is because p2 will not be "wired into" the promise chain until control returns from p1.

这到底是什么意思?如果await先等待p1的promise解决,那么为什么p2会出现拒绝错误呢?我是异步函数的新手,非常感谢任何新见解!

问题是解释器在等待 p1 时并没有等待 p2 的 promise 解决。在它越过线 await p2 之前,p2 基本上是悬空的 - 它没有连接到任何其他东西 直到 它被 awaited。因此,如果 p2 在连接到 .catch 之前抛出 - 通过函数本身的 .catch,或通过 await,将其连接到外部 .catch - 你会收到未处理的拒绝。

说明相同问题的另一种方式,仅使用一个 Promise:

function foo() {
   const p2 = new Promise((_,reject) => setTimeout(() => reject('2'), 500))
   setTimeout(() => {
     p2.catch(() => {});
   }, 1000);
}
foo();

在您的代码段示例中,p1 的重要性仅在于它会在遇到 await p2 表达式之前造成延迟。在我上面的示例中,setTimeout 正在做类似的事情 - 它附加了一个 .catch 处理程序 承诺被拒绝后,导致未处理的拒绝。

在您的程序中添加一些 console.log 语句将有助于您查看操作顺序

async function foo() {
   console.log("foo")
   const p1 = new Promise((resolve) => {
     console.log("p1 promise")
     setTimeout(_ => {
       console.log("p1 resolve")
       resolve('1')
     }, 1000)
   })
   const p2 = new Promise((_,reject) => {
     console.log("p2 promise")
     setTimeout(_ => {
       console.log("p2 reject")
       reject('2')
     }, 500)
   })
   console.log("results") 
   return [
     (console.log("await p1"), await p1),     
     (console.log("await p2"), await p2)
   ]
   
}
foo().then(console.log, console.error)

输出

order console.log
1 foo
2 p1 promise
3 p2 promise
4 results
5 await p1
6 p2 reject
7 p1 resolve
8 await p2
9 Error: 2

说明

  1. 所以当我们运行foo时,预计我们会看到消息1"foo" ,首先,因为那是程序的第一行。

  2. 下一个 p1 被创建,我们看到消息 2“p1 promise”。这表明 new Promise(... => body)body 立即是 运行。

  3. 下一个 p2 被创建,我们看到消息 3"p2 promise",如下同上解释。

  4. 接下来我们看到消息4“结果”。如果您希望看到 setTimeout 内的消息,这些消息在事件队列中会延迟,我们稍后会看到它们。这是 setTimeout

    的明确目的
  5. 接下来是消息5“await p1”,我们正在等待p1解决。

  6. 当我们等待 p1 解决时,p2 拒绝并且我们看到消息 6 “p2 拒绝”.

  7. p1 终于解决了,我们看到消息 7, "p1 resolve".

  8. 接下来我们移动到结果数组中的最终值,我们发出消息 8"await p2". p2此时已经完成,导致拒绝错误。此时 foo 立即退出,对 foo() 的调用导致拒绝承诺。如果这个点之后还有代码,就不会是运行了。这与 throwing 同步代码中的错误相同。

  9. 最后我们看到消息9, "Error: 2",这是[=27的结果=] 捕获 foo()

    返回的被拒绝的承诺