1. ホーム
  2. javascript

[解決済み] キャッチの配置 BEFOREとAFTER then

2022-05-10 23:10:02

質問事項

の違いがよくわかりません。 .catch ネストされたプロミスの中で、BEFOREとAFTERの次に。

選択肢1.

test1Async(10).then((res) => {
  return test2Async(22)
    .then((res) => {
      return test3Async(100);
    }).catch((err) => {
      throw "ERROR AFTER THEN";
    });
}).then((res) => {
  console.log(res);
}).catch((err) => {
  console.log(err);
});

選択肢2

test1Async(10).then((res) => {
   return test2Async(22)
     .catch((err) => {
        throw "ERROR BEFORE THEN";
      })
      .then((res) => {
        return test3Async(100);
      });
  }).then((res) => {
    console.log(res);
  }).catch((err) => {
    console.log(err);
  });

各関数の動作は以下のとおりで、test1 は数値が <0 test2 は数字が > 10 でない場合、test3 は失敗します。 100 . この場合、test2が失敗しているだけです。

私はテスト2Asyncを実行して失敗させようとしましたが、BEFOREとAFTERの両方が同じように動作し、それはテスト3Asyncが実行されていないことです。誰か私に異なる場所にcatchを配置するための主な違いを説明することができますか?

各関数で私は console.log('Running test X') が実行されるかどうかをチェックするためです。

この質問は、私が投稿した前スレッドのために発生します。 ネストされたコールバックをプロミスに変換するには? . これは別の問題であり、別のトピックを投稿する価値があると思います。

解決方法は?

つまり、基本的には、この2つの違いは何かということですね(ここで p は以前のコードから作成されたプロミスです)。

return p.then(...).catch(...);

そして

return p.catch(...).then(...);

p が解決するときと拒否するときのどちらにも違いがありますが、その違いが問題になるかどうかは .then() または .catch() ハンドラによって行われます。

が発生するとどうなるか? p が解決します。

最初のスキームでは p が解決されると .then() ハンドラが呼ばれる。 もし、その .then() ハンドラは値を返すか、最終的に解決される別のプロミスを返します。 .catch() ハンドラはスキップされます。 しかし、もし .then() ハンドラが投げたり、最終的に拒否されるプロミスを返したりすると .catch() ハンドラは、元のプロミスが拒否された場合にも p で発生したエラーだけでなく .then() ハンドラです。

2番目のスキームでは p が解決されると .then() ハンドラが呼ばれる。 もし、その .then() ハンドラが投げるか、最終的に拒否するプロミスを返せば .catch() ハンドラはそれを捕らえることができません。なぜなら、チェーンの中でハンドラの前にいるからです。

つまり、これが違いその1です。 もし .catch() ハンドラが AFTER にある場合、そのハンドラの内部で発生したエラーも捕捉することができます。 .then() ハンドラです。

が発生するとどうなるか? p を拒否します。

さて、最初のスキームにおいて、もし約束事である p が拒否した場合 .then() ハンドラはスキップされ .catch() ハンドラは期待通りに呼び出されます。 このとき .catch() ハンドラによって、最終的に何が返されるかが決まります。 もし、単に .catch() ハンドラや、最終的に解決するプロミスを返した場合、エラーを "処理" して正常に返したため、プロミスチェーンは解決した状態に切り替わります。 の中で拒否されたプロミスを投げたり返したりすると、プロミスの連鎖は解決された状態に切り替わります。 .catch() ハンドラでは、返されたプロミスは拒否されたままです。

2番目の方式では、プロミス p が拒否された場合 .catch() ハンドラが呼び出されます。 通常の値や、最終的に解決するプロミスを返した場合は .catch() ハンドラ(つまりエラーを処理する)では、プロミスの連鎖が解決済みの状態に切り替わり、さらに .then() ハンドラの後に .catch() が呼び出されます。

というわけで、違いその2です。 もし .catch() ハンドラがBEFOREであれば、エラーを処理することができます。 .then() ハンドラを呼び出すことができます。

いつwhichを使うか。

を1つだけ使用したい場合は、最初のスキームを使用します。 .catch() ハンドラで、元のプロミスである p または .then() ハンドラから拒否され p はスキップする必要があります。 .then() ハンドラを使用します。

元のプロミスのエラーをキャッチできるようにしたい場合は、2番目のスキームを使用します。 p を実行し、(条件次第では)プロミスの連鎖を解決済みとして継続させることができるかもしれません。 .then() ハンドラを使用します。

もう一つの選択肢

に渡すことができる両方のコールバックを使用する、もう一つのオプションがあります。 .then() というように

 p.then(fn1, fn2)

のうちの1つだけが保証されます。 fn1 または fn2 が呼ばれることはありません。 もし p が解決されると fn1 が呼び出されます。 もし p が拒否された場合 fn2 が呼び出されます。 での結果の変更はありません。 fn1 にすることはできません。 fn2 が呼び出されたり、その逆もあります。 ですから、ハンドラの中で何が起ころうとも、2つのハンドラのうち1つだけが確実に呼び出されるようにしたい場合は p.then(fn1, fn2) .