在 try/catch 块中等待两个承诺会导致“未处理的承诺拒绝”

old*_*ard 8 node.js async-await typescript

我想等待两个并行运行的承诺。我不想连续等待每个承诺(这有效但速度较慢)。

出于这个原因,我认为我可以首先创建两个承诺来让它们滚动,比如说两个网络请求,然后等待它们并能够在 catch 块中捕获错误。这个假设似乎是不正确的,因为我在运行此示例代码时收到警告。

  • 这是为什么?
  • 如何最好地并行运行两个或多个网络请求,否则使用优雅的代码?
  • 为什么 Typescript 没有警告我 catch 块不会捕获拒绝?
async function testMultipleAwait() {
  try {
    const aPromise = new Promise((resolve) => {
      setTimeout(() => resolve('a'), 200);
    });

    const bPromise = new Promise((_, reject) => {
      setTimeout(() => reject('b'), 100);
    });

    const a = await aPromise;
    const b = await bPromise;
  } catch (e) {
    console.log('Caught error', e);
  }
}

testMultipleAwait();
Run Code Online (Sandbox Code Playgroud)

不会导致“捕获错误”输出,而是我得到

tsc test-try-catch-await.ts && node test-try-catch-await.js

(node:31755) UnhandledPromiseRejectionWarning: b
(node:31755) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:31755) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Caught error b
(node:31755) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
Run Code Online (Sandbox Code Playgroud)

Jef*_*amp 7

我想我知道问题是什么。尽管这些承诺以并发方式启动,但您仍在等待aPromise并按bPromise顺序:

const a = await aPromise; // First await this...
const b = await bPromise; // and then start to await this
Run Code Online (Sandbox Code Playgroud)

当这两个承诺都兑现时,这就不是什么大问题了。它会让你等待尽可能多的时间Promise.all,然后愉快地继续。这就是为什么这个问题根本不那么明显......

重要的是要知道,在底层,由于 async/await,这个 try-catch 被转换为一个承诺。这意味着首先等待的语句之后的任何内容都将最终出现在promise.then 回调函数中。

因此,在到达const b = await bPromise之前(200 毫秒后)不会运行。提前 100 毫秒失败。const abPromise

这并不是说 async/await 不会发现错误或catch完全附加您的块(如promise.catch(...))。毕竟,节点警告和 catch 处理程序都有终端输出:

tsc test-try-catch-await.ts && node test-try-catch-await.js

1 first node sees the error     > (node:31755) UnhandledPromiseRejectionWarning: b
2                                 (node:31755) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
3                                 (node:31755) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
4 and then your catch handler   >      Caught error b
5                                 (node:31755) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
Run Code Online (Sandbox Code Playgroud)

bPromise所以 de catch 子句确实有效,但异步函数直到至少 200 毫秒后才将其附加到。第 5 行似乎证实了这一点:

PromiseRejectionHandledWarning: Promise rejection was handled asynchronously.
Run Code Online (Sandbox Code Playgroud)

一旦微任务队列为空,就会抛出拒绝错误。

承诺拒绝已处理,但节点认为您已经太晚了。您可以使用 解决此问题Promise.all。这样,您await和您的异步函数将首先捕获每个潜在的错误。

// Everything just as it is.. and then:

const [a, b] = await Promise.all([
    aPromise, 
    bPromise,
]);
Run Code Online (Sandbox Code Playgroud)

因为我很好奇,所以我在 chrome 控制台中输入了您的代码,看看会发生什么。错误日志会在很短的时间内弹出(我猜是 100 毫秒)。看看这个输出,你可以听到 chrome 说:

“啊等等!它终于被抓住了。这是消息!”

点击查看 gif 动画。

运行代码后的 chrome 输出