【问题标题】:How does the order of concurrent promises work in an asynchronous function?并发 Promise 的顺序如何在异步函数中工作?
【发布时间】:2021-05-09 19:16:47
【问题描述】:

我注意到来自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 声明:

在以下代码中,将抛出未处理的承诺拒绝错误,即使 .catch 处理程序已在承诺链中进一步配置。这是因为在控制权从 p1 返回之前,p2 不会“连接”到承诺链中。

这究竟是什么意思?如果await 等待p1 的承诺首先解决,那么为什么p2 会出现拒绝错误?我对异步函数非常陌生,感谢任何新见解!

【问题讨论】:

    标签: javascript asynchronous concurrency promise


    【解决方案1】:

    问题在于解释器在等待 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();
    

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

    【讨论】:

      【解决方案2】:

      在您的程序中添加一些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 reject”

      7. p1 最终解析,我们看到消息 7“p1 resolve”

      8. 接下来,我们移动到结果数组中的最终值,并显示消息 8“await p2”p2 此时已经实现,并导致拒绝错误。此时foo 立即退出并且对foo() 的调用导致被拒绝的promise。如果在此之后有代码,它将不会运行。这与throw同步代码中的错误相同。

      9. 最后我们看到消息9“Error: 2”,这是console.error捕获foo()返回的rejected promise的结果

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-22
        • 1970-01-01
        • 2021-02-15
        • 2017-03-19
        • 1970-01-01
        • 2017-05-18
        相关资源
        最近更新 更多