web-dev-qa-db-ja.com

Promise.all内のエラーハンドラー

私はこのコードを調べていますが、それが機能している間、私は間違っていると感じています。アンチパターンを見ているのかしら?

コードは、2つのプロミスgetAccountsgetTransactionsで始まります。 promiseの1つには、エラーを処理しますが、friendlyに見えるオブジェクトを含む解決済みpromiseを返すcatchブロックがあります。

let accounts = getAccounts()
                   .catch(error => Promise.resolve({errorCode: M011}));

let transactions = getTransactions();

これらはPromise.allで使用されます。

Promise.all([accounts, transactions])
       .then(results => createStatement(results));

getAccountsが失敗すると、Promise.allfail fastになるはずだと思ったので、これは私には間違っているように見えます。しかし一方で、getAccountsの失敗はできるだけ早く処理されますが、これは確かに良いことですか?それについての唯一のことは、それが別のPromise.rejectで返らないことです

与えられた理論的根拠は、この方法でPromise.allが窒息しないことでした。もちろん、もう1つの質問は、なぜこのコードが最初にPromise.allを使用するのかということです。わからないけど、レガシーコード。

1
piratemurray

これはアンチパターンではありません。これはコードのにおいです。つまり、これが可能である場合には、回避する必要がある種類のことですが、他に何も役立たない正当な場合もあります。

私は、Promise.allがfail fast。であるべきだと思いました。

うん。これが、Promise.allのデフォルトの動作がすぐに失敗する理由です。

与えられた理論的根拠は、このようにPromise.allが窒息しないということでした。

これは、一部の約束が拒否されたとしても、正常に解決された他の約束で何か有用なことができるという状況にいることを意味します。これは間違いなく珍しい状況ではありません。

もちろん、もう1つの疑問は、このコードの一部がそもそもなぜPromise.allを使用しているのかということです。

おそらく、多くのプロミスが解決したにもかかわらず、あなたができる便利なことは、すべて解決した後でしか実行できないためです。


ここで、Promiseが銀行取引を表し、UIが取引が成功したかどうかに基づいて緑色または赤色のテキストを表示するとします。

一部のトランザクションのみが成功し、他のトランザクションが失敗した場合は、「チョーク」して情報のない単一の「1つ以上のトランザクションが失敗した可能性があります」ではなく、成功したトランザクションを緑色で、失敗したトランザクションを赤色で表示することをお勧めします。メッセージ。そのような状況では、次のようなコードに異議を唱える人は想像できません。

let resultRowPromise = executeTransactions(desiredTransactions)
           .then(result => Promise.resolve({ color: "green", message: "Success =D" }))
           .catch(error => Promise.resolve({ color: "red",   message: "Fail ;_;" }));

これは、いつかPromise.allで「ループオーバー」する可能性があります。

これは、根底にある約束を拒否することが理にかなっており、そのような約束のセットが完了するのを待つことが理にかなっており、すべての失敗を失敗として扱うのではなく、約束ごとに失敗を処理することが理にかなっている全体のバッチ。

しかし、それらのいずれかがgetAccounts()の例に当てはまらない場合は、根本的なプロミスを最初から拒否しないようにする、Promise.allを待つ代わりに各プロミスの解決に個別に対応するなどの代替策を検討する必要があります。あなたの場合、成功したものを無視しても大丈夫であれば、単にPromise.allを速く失敗させるだけです。

実際、先ほど挙げた例でも、必ずしもこれらの基準を満たしているとは限りません。各トランザクションプロミスを個別に処理することもできるため、ユーザーには「トランザクション1が成功しました」と表示されます。そして数秒後、「トランザクション2が失敗しました!」。次に、これらのメッセージをレンダリングするためのPromise.allを実行して(レンダリングエラーがない限り、これはshould常に成功します)、「すべてのトランザクションが成功しました!」などのメッセージを追加できます。または「3/10トランザクションが失敗しました!」一番上に。


プロミスが結果とエラーをどのように伝播するかについて考えるとき、値を返し、例外をスロー/キャッチする同等の「通常」、「同期」、または「命令的」な非プロミスコードを検討すると役立つことがよくあります。あなたの例では、それはおそらく:

var results = [];
for(let i = 0; i < accountIds.length; ++i) {
    try {
        var account = getAccount(accountIds[i]);
        results.Push(account);
    } catch(e) {
        results.Push({ errorCode: M011 });
    }
}

上で述べたすべてがこのコードにも当てはまりますが、このように見ると、なぜそれが当てはまるのかがより明確になるかもしれません。要約すると、この可能性は正当なものですが、正当化が確実に必要であり、正当化が成り立つかどうか、またはより明確な代替案があるかどうかを検討する価値は間違いありません。

1
Ixrec