无法捕获 for wait of 循环中的错误

Mic*_*ler 5 node.js async-await

我正在阅读MDN 上描述的“for wait of循环” 。它看起来令人印象深刻,所以我玩了一些代码,但令人惊讶的是我无法捕获那里抛出的错误。

'use strict';

const main = async() => {
  const bar = [];
  bar.push(new Promise((res) => { setTimeout(() => res(1), 1200); }));
  bar.push(new Promise((res) => { setTimeout(() => res(2), 800); }));
  bar.push(new Promise((res, rej) => { setTimeout(() => rej(3), 200); }));

  try {
    for await (const foo of bar) {
      console.log('hey', foo);
    }
  } catch (err) {
    console.error('err', err);
  }
};

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

我的输出主要是像我预期的那样。但我不明白,为什么我会收到 UnhandledPromiseRejection?我什至没有发现那个错误吗?

$> node await-loop.js 
(node:10704) UnhandledPromiseRejectionWarning: 3
(node:10704) 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:10704) [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.
hey 1
hey 2
err 3
(node:10704) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
Run Code Online (Sandbox Code Playgroud)

有人可以帮我理解并在这里写一个正确的口号吗?我错过了什么吗?

156*_*223 1

未处理的 Promise 拒绝?

我什至没有发现那个错误吗?

理论上是的。(这就是 catch 块的用途,对吧?)

从技术上讲没有。

Main Stack
|  try             |
|                  |
|    await bar[0]  | <-- waiting to resolve till sometime after 1200
|                  |
|  catch           |
|                  |
Run Code Online (Sandbox Code Playgroud)

(大约)200 毫秒后

bar[2] 被拒绝并推送到队列,但 wait 没有屈服,因为它仍在等待 bar[0] 屈服,这仅在 1200 毫秒后发生

因此,在 bar[2] 被拒绝时,没有catch可用的块来处理rejected promise. 请参阅上面的堆栈并注意,在拒绝时,try..catchbar[2]不在同一个堆栈中,至少对于编译器而言(或概念上对于 javascript)。

但你注意到:err 3当finally等待产生时,catch块捕获了哪些内容bar[2]

如果您更改承诺的顺序并将被拒绝的承诺作为数组中的第一项,您将看到 catch 块运行良好。

或者等待不同的情况:

// unhandled rejection
try {
  await bar[0]
  await bar[1]
  await bar[2]
} catch (e) {
  console.error('error', e)
}

// Catch successfull
try {
  await bar[2]
  await bar[0]
  await bar[1]
} catch (e) {
  console.error('error', e)
}
Run Code Online (Sandbox Code Playgroud)

更新:

更好的方法是使用Promise.all,它具有快速失败的行为。

try {
  const datas = await Promise.all(bar)
} catch (e) {
  console.error(e)
}
Run Code Online (Sandbox Code Playgroud)