web-dev-qa-db-ja.com

JavaScriptの非同期関数ですべての約束拒否をキャッチする

複数のプロミスが非同期関数(javaScript-ノードv8.4.0)で待機された後に拒否エラーをスローすると、すべてのエラーをキャッチする問題に遭遇しました。

次のjavaScriptへの参照を作成します。

参考までに、関数timeoutOne()およびtimeoutTwo()は、それぞれ1秒および2秒のタイムアウト後に値を解決するネイティブpromiseを返すか、「deviousState」をtrueに設定するとエラーで拒否します。

let deviousState = true;

async function asyncParallel() {
  try {
    let res1 = timeoutOne();
    let res2 = timeoutTwo();
    console.log(`All done with ${await res1} ${await res2}`)
  }
  catch(err) {
    console.log(err)
  }
}
asyncParallel();

let pAll = Promise.all([timeoutOne(), timeoutTwo()]);
pAll.then((val) => {
  console.log(`All done with ${val[0]} ${val[1]}`)
}).catch(console.log);

どちらの場合も、最初に返されるpromiseのみがエラーを記録します。私はいくつかのPromiseライブラリにすべてのエラーを記録する方法があることを知っています(たとえば、bluebirdの「settle」メソッド)が、ネイティブPromiseにこのメソッドに類似するものがあるかどうかわかりませんか?

また、両方のプロミスがリジェクトする場合、asyncParallel()は最後にリジェクトするプロミスでキャッチされていないエラーをログに記録します。これは、非同期関数のtry/catchブロックがこの方法で複数の拒否をキャッチするためのメカニズムが組み込まれていないためですか?

約束が解決すれば、両方のインスタンスですべてが同じように機能します。その両方が拒否されると、Promise.allがエラーを処理し、非同期関数バージョンは、未処理のpromiseエラーの1つがノードの将来のバージョンでプロセスをクラッシュさせると述べています。

とにかく、このタイプのエラーを正しく処理するためのtry/catchの方法はありますか?または、エラーが正しく処理されることを確認するために、非同期関数内でPromise.allを使用する必要がありますか?

8
MFave

両方のプロミスが拒否された場合、asyncParallel()は最後に拒否されたプロミスとともに、キャッチされていないエラーを記録します。

はい-timeoutTwo() promiseを作成しましたが、エラーを処理したことはありません(awaitで使用するなど)。 _await res2_の例外のため、_await res1_は実行されませんでした。

(これは「最後を拒否する約束」ではなく、常に2番目に待っている約束です)。

これは、非同期関数のtry/catchブロックがこの方法で複数の拒否をキャッチするためのメカニズムが組み込まれていないためですか?

順次コードでは、複数の例外が存在することはできないため、それらに対処するための追加の構文を考えるのは難しいでしょう。

エラーが正しく処理されるように、非同期関数内で_Promise.all_を使用する必要がありますか?

はい、まさにそのとおりです。複数のプロミスを並行して待ちたい場合、always use _Promise.all_を使用する必要があります。 awaitキーワードは、次の.then()呼び出しの単なるシュガーです。

あなたは書くべきです

_async function asyncParallel() {
  try {
    let [val1, val2] = await Promise.all([timeoutOne(), timeoutTwo()]);
    console.log(`All done with ${val1} ${val2}`)
  } catch(err) {
    console.log(err)
  }
}
_

どちらの場合も、最初に返されるpromiseのみがエラーを記録します。私はいくつかのPromiseライブラリにすべてのエラーを記録する方法があることを知っています(たとえば、bluebirdの「settle」メソッド)が、ネイティブPromiseにこのメソッドに類似するものがあるかどうかわかりませんか?

いいえ、ありません。 settleの特性は、thenを使用して自分で実装するのは簡単で、任意の値を使用できます。

_async function asyncParallel() {
  try {
    let [stat1, stat2] = await Promise.all([
        timeoutOne().then(() => "one fulfilled", () => "one rejected"), 
        timeoutTwo().then(() => "two fulfilled", () => "two rejected")
    ]);
    console.log(`All settled with ${stat1} ${stat2}`)
  } catch(err) {
    console.log(err)
  }
}
_
8
Bergi