プロミスキャッチの再スローエラー


88

チュートリアルで次のコードを見つけました。

promise.then(function(result){
    //some code
}).catch(function(error) {
    throw(error);
});

私は少し混乱しています:catch呼び出しは何かを達成しますか?キャッチされたのと同じエラーをスローするだけなので、効果がないように思えます。これは、通常のtry / catchがどのように機能するかに基づいています。


チュートリアルへのリンクを提供していただけますか?たぶん、参考になる追加のコンテキストが...そこにある
イゴール

@Igorできません、Pluralsightにあります。これはおそらく、エラー処理ロジックの単なるプレースホルダーですか?
タイラーダーデン2017

それは、エラーを呼び出し元に渡すだけなので、私が推測することです。これは、最初にキャッチがないことによっても達成できます。
イゴール

1
@TylerDurdenプレースホルダーであることについてあなたは正しいと思います。
Jared Smith

@TylerDurden、それもプレースホルダーだと思います。たぶん、エラーをフォーマット/正規化する方法をデモンストレーションしようとしています。基本的に約束-に相当しtry { ... }catch(error){ throw new Error("something went wrong") }ます。または、PromiseとErrorsに互換性があることを示すために(少なくともその方法で)。しかし、現在の実装では、それはばかげています。そうです、それは何もしませんし、継承クラスでそれを上書きできるようにするためにOOPに追加するフックのようなものでもありません。何かができたらすぐにキャッチブロックを追加しますが、プレースホルダーとしてだけでなく、そのようにはしません。
トーマス

回答:


124

あなたが示すように、裸のキャッチアンドスローには意味がありません。コードを追加して実行を遅くする以外は、何の役にも立ちません。したがって、行って.catch()再スローする場合は、でやりたいことがあるはずです。.catch()そうでない場合は、.catch()完全に削除する必要があります。

その一般的な構造の通常のポイントは.catch()、エラーのログ記録や一部の状態のクリーンアップ(ファイルのクローズなど)などで何かを実行したいが、Promiseチェーンを拒否されたまま継続したい場合です。

promise.then(function(result){
    //some code
}).catch(function(error) {
    // log and rethrow 
    console.log(error);
    throw error;
});

チュートリアルでは、エラーをキャッチできる場所を示したり、エラーを処理してから再スローしたりする概念を教えるためだけに存在する場合があります。


キャッチと再スローの便利な理由のいくつかは次のとおりです。

  1. エラーログに記録したいが、Promiseチェーンは拒否されたままにしておきます。
  2. エラーを他のエラーに変換したい(多くの場合、チェーンの最後でエラー処理を簡単にするため)。この場合、別のエラーを再スローします。
  3. あなたはしたい約束チェーンを続行する前に、処理の束を行う(例えば近い/無料リソースとして)しかし、あなたが約束チェーンが拒否滞在したいです。
  4. 障害が発生した場合に、Promiseチェーンのこの時点でデバッガーのブレークポイントを配置するスポットが必要です。

ただし、catchハンドラーに他のコードがない状態で同じエラーを単純にキャッチして再スローしても、コードの通常の実行には何の役にも立ちません。


私の意見では、それは良い例ではありません。このようなアプローチを使用すると、1つのエラーに対して複数のログを簡単に取得できます。Javathrow new Exception(periousException);では、javascriptがネストされたエラーをサポートしているかどうかはわかりませんが、とにかく「ログアンドスロー」は悪い習慣です。
チェリー

26
@ Cherry-これが一般的に悪い習慣であるとは言えません。モジュールが独自の方法で独自のエラーをログに記録したい場合があり、これはそのための1つの方法です。その上、私はこれをお勧めしません、私は.catch()あなたがで何か他のことをしない限り、キャッチの中に同じエラーを投げる理由がないことを説明しているだけです.catch()。それがこの答えのポイントです。
jfriend00 2017

一般に、例外は抽象化のレベルに適合している必要があります。たとえば、db関連の例外をキャッチし、呼び出し元によって処理される「サービス」例外のようなものをスローすることはまったく問題ありません。これは、低レベルの例外に関する詳細を公開しない場合に特に役立ちます
maxTrialfire 2018

3
キャッチして(場合によっては)スローするもう1つの理由は、特定のエラーを処理することですが、それ以外はすべて再スローします。
ジャスパー

2
@ SimonZyx-はい、.finally()そのために非常に便利ですが、リソースがエラー以外のパスですでに処理されている場合があるため、リソース.catch()を閉じる場所でもあります。それは本当に状況に依存します。
jfriend00

15

.then().catch()メソッドの両方がPromisesを返し、いずれかのハンドラーでExceptionをスローすると、返されたPromiseは拒否され、Exceptionは次のrejectハンドラーでキャッチされます。

次のコードでは、最初.catch()ので例外をスローし、2番目のコードでキャッチします.catch()

new Promise((resolve, reject) => {
    console.log('Initial');

    resolve();
})
.then(() => {
    throw new Error('Something failed');
        
    console.log('Do this'); // Never reached
})
.catch(() => {
    console.log('Something failed');
    throw new Error('Something failed again');
})
.catch((error) => {
    console.log('Final error : ', error.message);
});

2番目.catch()は実行されたPromisedを返し、.then()ハンドラーを呼び出すことができます:

new Promise((resolve, reject) => {
    console.log('Initial');

    resolve();
})
.then(() => {
    throw new Error('Something failed');
        
    console.log('Do this'); // Never reached
})
.catch(() => {
    console.log('Something failed');
    throw new Error('Something failed again');
})
.catch((error) => {
    console.log('Final error : ', error.message);
})
.then(() => {
    console.log('Show this message whatever happened before');
});

便利なリファレンス:https//developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#Chaining_after_a_catch

お役に立てれば!


4

catchメソッド呼び出しを完全に省略しても、重要な違いはありません。

それが追加する唯一のことは、余分なマイクロタスクです。これは、実際には、catch条項なしで失敗する約束の場合よりも後で約束の拒否に気付くことを意味します。

次のスニペットはこれを示しています。

var p;
// Case 1: with catch
p = Promise.reject('my error 1')
       .catch(function(error) {
          throw(error);
       });

p.catch( error => console.log(error) );
// Case 2: without catch
p = Promise.reject('my error 2');

p.catch( error => console.log(error) );

最初の拒否の前に2番目の拒否がどのように報告されるかに注意してください。それが唯一の違いです。


3

つまり、あなたの質問は「プロミスチェーンでは、.catch()メソッドは何をするのか」ということのように聞こえます。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw

throwステートメントは「停止し(throw後のステートメントは実行されません)、制御は呼び出しスタックの最初のcatchブロックに渡されます。呼び出し元の関数間にcatchブロックが存在しない場合、プログラムは終了します。」

promiseチェーンでは、.then()メソッドはある種のデータチャンクを返します。このチャンクの返却により、約束が完了します。データが正常に返されると、約束が完了します。.catch()同じように考えることができます。 .catch()ただし、失敗したデータの取得は処理されます。throwステートメントは約束を完了します。時折、開発者が使用するの.catch((err) => {console.log(err))} を目にすることがありますが、これもプロミスチェーンを完成させます。


0

実際には再スローする必要はありません。Promise.catchを空のままにしてください。そうしないと、拒否を処理しないと見なされ、コードをtry catchでラップすると、渡されるエラーが自動的にキャッチされます。

try{
  promise.then(function(result){
    //some code
  }).catch(function(error) {
    //no need for re throwing or any coding. but leave this as this otherwise it will consider as un handled
  });
}catch(e){
  console.log(e);
  //error can handle in here
}

0

promiseチェーンでは、.catchを使用することをお勧めします

関数f2の例:.then(...)。catch(e => require(e));

  • test1-trycatchを使用
  • test2-tryまたは.catchなし
  • test3-.catchを使用

function f1() {
    return new Promise((resolve, reject) => {
        throw new Error('test');
    });
}

function f2() {
    return new Promise((resolve, reject) => {
        f1().then(value => {
            console.log('f1 ok ???');
        }).catch(e => reject(e));
    });
}

function test1() {
    console.log('test1 - with try catch - look in F12');
    try {
      f2().then(() => { // Uncaught (in promise) Error: test
        console.log('???'); });
    } catch (e) {
      console.log('this error dont catched');
    }
}

function test2() {
    console.log('test2 - without try or .catch - look in F12');
    f2(); // Uncaught (in promise) Error: test
}

function test3() {
  console.log('test3 - with .catch');
  f2().then(value => {
    console.log('??');
  }).catch(e => {
    console.log(' now its ok, error ', e);
  })
}

setTimeout(() => { test1(); 
  setTimeout(() => { test2(); 
    setTimeout(() => { test3(); 
    }, 100);
  }, 100);
}, 100);

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.