web-dev-qa-db-ja.com

約束のその時と最後の違いは何ですか?

Bluebirdの finally のドキュメントはありますが、thenとの違いはまだよくわかりません。

明確にするために、thenの後にcatchが呼び出される理由を正確に知っています。 Iwantキャッチ後に呼び出されます。それが意図です。私の質問は次のとおりです:Iwantコードがpromiseの状態に関係なく常に実行される場合、thenfinallyそのために?

私はこのテストを作成しました:

_var Promise = require("bluebird");

function test1 () {
    console.log("RESOLVE + THEN + CATCH + THEN");
    return new Promise((resolve, reject) => resolve())
       .then(() => console.log("then"))
       .catch(err => console.log("error:", err.message))
       .then(() => console.log("end"));
}

function test2 () {
    console.log("REJECT + THEN + CATCH + THEN");
    return new Promise((resolve, reject) => reject(new Error("rejected")))
       .then(() => console.log("then"))
       .catch(err => console.log("error:", err.message))
       .then(() => console.log("end"));
}

function test3 () {
    console.log("RESOLVE + THEN + CATCH + FINALLY");
    return new Promise((resolve, reject) => resolve())
       .then(() => console.log("then"))
       .catch(err => console.log("error:", err.message))
       .finally(() => console.log("end"));
}

function test4 () {
    console.log("REJECT + THEN + CATCH + FINALLY");
    return new Promise((resolve, reject) => reject(new Error("rejected")))
       .then(() => console.log("then"))
       .catch(err => console.log("error:", err.message))
       .finally(() => console.log("end"));
}

// run tests "sequentially" so console output doesn't get blended
setTimeout(test1, 500);
setTimeout(test2, 1000);
setTimeout(test3, 1500);
setTimeout(test4, 2000);
_

これは4つのケースをテストします。

  1. .then(...).catch(...).then(...)約束の解決済み。
  2. .then(...).catch(...).then(...)は、約束を拒否しました。
  3. .then(...).catch(...).finally(...)約束の解決済み。
  4. .then(...).catch(...).finally(...)は、約束を拒否しました。

私が見る結果は、1 + 2が3 + 4と同じように振る舞うケースです:最後のビット(テストに応じてthenまたはfinally)は、意図したとおりに、それより前に何が起きても実行されます。そのプログラムの出力は次のとおりです。

_RESOLVE + THEN + CATCH + THEN
then
end
REJECT + THEN + CATCH + THEN
error: rejected
end
RESOLVE + THEN + CATCH + FINALLY
then
end
REJECT + THEN + CATCH + FINALLY
error: rejected
end
_

さて、私が尋ねている理由は、 私が尋ねたこの他の質問についてのコメント

約束がサポートするかどうかはわかりませんが、最後の_.then_を_.finally_に変更して、busyが常にクリアされるようにする必要があります。

thenについての私の非常に限られた知識と上記のテストから、thenで十分であるように思われます。しかし、そのコメントの後、私は自分自身とthenを使用して「最終的に」コードを実行することの安全性に疑問を抱いています。

だから私の質問は:thenfinallyの違いは何ですか? lookは同じように動作しますが、いつfinallyの代わりにthenを使用する必要がありますか?

12
Jason C

最初の違い:エラーが発生した場所でエラーをキャッチしたくない場合がありますが、この関数を使用するコードでは、エラーをキャッチしません。その場合、then()finally()を置き換えることはできません。

エラーが発生したかどうかに関係なく、何かをクリーンアップする必要がある場合があります(参照の無効化、タイムアウトのクリアなど)。そこでfinally()を使用します。

2番目の違い:catch()に渡す関数もスローする可能性があります。その場合、Promiseが拒否され、次のthen()は呼び出されません。

(したがって、最終的にcatchがエラーで実行される前に、それを知りませんでした)

ええ、それがfinally()のポイントです。解決された値を変更せずに、どんな状況でも実行されます。

try {} finally {}、キャッチなし。

13
Thomas

.then.finallyは同じではありません。

.thenは主要なPromiseプリミティブです。 Promises/A + spec で徹底的に定義されており、すべてのpromiseライブラリがそれを実装します。

Bluebird .finally ハンドラーは、「約束の運命に関係なく呼び出されます」。したがって、未処理の例外は依然として.finallyをトリガーします。

new Promise((resolve, reject) => reject(false))
  .finally(a => console.log('finally', a))
// finally undefined
// Unhandled rejection false

new Promise((resolve, reject) => reject(false))
  .then(a => console.log('then', a))
// Unhandled rejection false

.finallyは、promiseの解決された値を変更せず、promiseチェーンの結果を受け取りません。

new Promise((resolve, reject) => reject(false))
  .catch(e => {
    console.log(e)
    return 2
  })
  .finally(a => {
    console.log('finally', a)
    return 1
  })
  .then(res => console.log('res', res))
// finally undefined
// res 2

テストはすべてのエラーをキャッチし、フロー制御にプロミスのみを使用し、プロミスチェーンに沿って解決/拒否される値に依存しないため、メソッドはテストケースで似ています。

4
Matt

大丈夫、いくつかのチャットとKevinBの多くの助けの後、少なくとも1つの違いを見つけました。次の2つの新しいテストを検討してください。

function test5 () {
    console.log("REJECT + THEN + CATCH/THROW + THEN");
    return new Promise((resolve, reject) => reject(new Error("rejected")))
       .then(() => console.log("then"))
       .catch(function(err) { throw new Error("error in catch"); })
       .then(() => console.log("end"));
}

function test6 () {
    console.log("REJECT + THEN + CATCH/THROW + FINALLY");
    return new Promise((resolve, reject) => reject(new Error("rejected")))
       .then(() => console.log("then"))
       .catch(function(err) { throw new Error("error in catch"); })
       .finally(() => console.log("end"));
}

これらでは、promiseは拒否されますが、catchからエラーがスローされます。

両方の場合、最終的にプロミスは拒否されますが、finallyの場合、finallyはまだ実行されますが、thenは実行されません。

それが違い。これらはalmostと同じですが、唯一の例外はcatchハンドラからエラーがスローされ、finallyが実行され、thenはしません。

これは、私が引用したコメントにもメリットがあることを意味します。エラーハンドラで別のエラーが発生した場合、thenはクリーンアップを保証しませんが、finallyはクリーンアップを保証します。それは私が行方不明だったケースです。

2
Jason C