web-dev-qa-db-ja.com

.then(success、fail)はいつプロミスのアンチパターンと見なされますか?

bluebird promise FAQ を見て、そこでは .then(success, fail)はアンチパターンです と言及されています。試行錯誤については、その説明がよくわかりません。次の何が問題なのですか?

some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })

この例では、以下を正しい方法として提案しているようです。

some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })

違いは何ですか?

161
user2127480

違いは何ですか?

.then()呼び出しは、コールバックがエラーをスローした場合に拒否されるプロミスを返します。これは、成功したloggerが失敗すると、エラーは次の.catch()コールバックに渡されますが、failと並んでいるsuccessコールバックには渡されません] _。

制御フローダイアグラムは次のとおりです。

control flow diagram of then with two argumentscontrol flow diagram of then catch chain

同期コードで表現するには:

_// some_promise_call().then(logger.log, logger.log)
then: {
    try {
        var results = some_call();
    } catch(e) {
        logger.log(e);
        break then;
    } // else
        logger.log(results);
}
_

2番目のlog.then()の最初の引数に似ています)は、例外が発生しなかった場合にのみ実行されます。ラベル付きブロックとbreakステートメントは少し奇妙に感じますが、これは実際には pythonが_try-except-else_ for (推奨読書!)です。

_// some_promise_call().then(logger.log).catch(logger.log)
try {
    var results = some_call();
    logger.log(results);
} catch(e) {
    logger.log(e);
}
_

catchロガーは、成功ロガー呼び出しからの例外も処理します。

違いはたくさんあります。

試行錯誤についての説明はよくわかりません

引数は、通常、処理のすべてのステップでエラーをキャッチすることであり、チェーンで使用しないでください。すべてのエラーを処理する最終ハンドラが1つだけであることが期待されます-一方、「アンチパターン」を使用すると、一部のthen-callbackのエラーは処理されません。

ただし、このパターンは実際には非常に便利です:正確にこのステップで発生したエラーを処理し、何かを実行したい場合完全に異なるエラーが発生しなかった場合、つまりエラーが回復不可能な場合。 注意してくださいこれは分岐あなたの制御フローであること。もちろん、これが望ましい場合もあります。


次の何が問題なのですか?

_some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })
_

コールバックを繰り返す必要があったこと。あなたはむしろ欲しい

_some_promise_call()
   .catch(function(e) {
       return e; // it's OK, we'll just log it
   })
   .done(function(res) {
       logger.log(res);
   });
_

これには .finally() を使用することも検討してください。

189
Bergi

2つはまったく同一ではありません。違いは、最初の例はsuccessハンドラーでスローされた例外をキャッチしないことです。そのため、メソッドが解決済みのプロミスのみを返す場合、よくあることですが、末尾のcatchハンドラー(または、空のthenパラメーターを持つ別のsuccess)が必要です。確かに、thenハンドラーは、潜在的に失敗する可能性のあることを何もしていない可能性があります。その場合、2つのパラメーターthenを1つ使用しても問題ありません。

しかし、リンク先のテキストのポイントは、thenが多くの非同期ステップをチェーンする機能においてコールバックと比較して最も有用であり、実際にこれを行うと、thenの2パラメーター形式は微妙に動作しないことだと思います上記の理由により、予想どおり。ミッドチェーンで使用すると特に直感に反します。

多くの複雑な非同期処理を行って、私が認める以上にこのようなコーナーにぶつかった人として、このアンチパターンを避け、個別のハンドラーアプローチを使用することを本当にお勧めします。

33
acjay

両方の長所と短所を調べることで、状況にどちらが適切かを計算で推測できます。これらは、約束を実装するための2つの主なアプローチです。どちらにもプラスとマイナスがあります

キャッチアプローチ

some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })

利点

  1. すべてのエラーは1つのcatchブロックで処理されます。
  2. Thenブロックの例外もキャッチします。
  3. 複数の成功コールバックの連鎖

欠点

  1. チェーンの場合、異なるエラーメッセージを表示することが難しくなります。

成功/エラーアプローチ

some_promise_call()
.then(function success(res) { logger.log(res) },
      function error(err) { logger.log(err) })

利点

  1. きめ細かなエラー制御が得られます。
  2. Dbエラー、500エラーなど、さまざまなカテゴリのエラーに共通のエラー処理機能を使用できます。

Disavantages

  1. 成功コールバックによってスローされたエラーを処理する場合は、さらに別のcatchが必要になります
17
aWebDeveloper

.then().catch()を使用すると、ワークフローを実現するために必要なPromise Chainingを有効にできます。データベースからいくつかの情報を読み取る必要があり、それを非同期APIに渡し、応答を操作する必要がある場合があります。応答をデータベースにプッシュすることができます。これらすべてのワークフローをコンセプトで処理することは実行可能ですが、管理が非常に困難です。より良い解決策はthen().then().then().then().catch()で、これは一度だけキャッチしてすべてのエラーを受け取り、コードのmaintainabilityを維持できます。

1
Jayant Varshney

簡単な説明:

ES2018で

引数onRejectedを指定してcatchメソッドが呼び出されると、次の手順が実行されます。

  1. Promiseをthisの値にします。
  2. 戻る? Invoke(promise、 "then"、"undefined、onRejected")。

つまり:

promise.then(f1).catch(f2)

等しい

promise.then(f1).then(undefiend, f2)
0
bitfishxyz