web-dev-qa-db-ja.com

Promiseでキャッチされない例外をキャッチする方法

Promise例外を含むすべての例外をグローバルにキャッチする方法はありますか。例:

    window.onerror = function myErrorHandler(errorMsg, url, lineNumber) {
        alert("Error occured: " + errorMsg);//or any message
        return false;
    }

    var myClass = function(){

    }


    var pr = new Promise(function(resolve, react){
        var myInstance = new myClass();
        myInstance.undefinedFunction(); // this will throw Exception
        resolve(myInstance);
    });


    pr.then(function(result){
        console.log(result);
    });

    // i know right will be this:
    // pr.then(function(result){
    //     console.log(result);
    // }).catch(function(e){
    //     console.log(e);
    // });

このスクリプトはエラーなしで静かに終了します。 firebugには何もありません。

私の質問は、もし私が間違いをして、それをキャッチするのを忘れたら、グローバルにキャッチする方法はありますか?

65
John

更新すると、ほとんどのブラウザでネイティブプロミスが次の処理を実行します。

window.addEventListener("unhandledrejection", function(promiseRejectionEvent) { 
    // handle error here, for example log   
});

先日、これについて議論していました。

Bluebirdでこれを行う方法は次のとおりです。

window.onpossiblyunhandledexception = function(){
    window.onerror.apply(this, arguments); // call
}

window.onerror = function(err){
    console.log(err); // logs all errors
}

Bluebirdでは、Promise.onPossiblyUnhandledRejectionを使用することもできます。ライブラリはQとは異なり未処理の拒否自体を検出するため、doneの呼び出しは必要ありません(更新2016-私はQのコードを作成し、これを実行します)。

ネイティブプロミスについては-それらはwill最終的にwindow.onerrorまたは新しいハンドラーに報告しますが、仕様プロセスはまだ完了していません-できます ここに従ってください

24

現在、ほとんどのpromise実装は、参照しているタイプの機能を提供していませんが、多くのサードパーティのpromiseライブラリ( Q および bluebird を含む)は、 done()メソッド。キャッチされていないエラーをキャッチして再スローし、コンソールに出力します。

Edit:キャッチされない例外を処理するためのBluebirdの機能に関するBenjamin Gruenbaumの回答を参照してください)

そのため、使用する約束はすべて返されるか、.done()で終了するという経験則に従う必要があります。

pr.then(function(result){
    console.log(result);
})
.done();

Q APIリファレンスから引用するには:

done vs. then使用法のゴールデンルールは、return誰かへの約束、またはチェーンがあなたで終わっている場合は、doneで終了します。 catchハンドラー自体がエラーをスローする可能性があるため、catchで終了するだけでは不十分です。

これにはまだ少し手間がかかることを理解していますが、これを行うのを忘れることはできますが、特に上記で指摘した理由により、.catch()およびすべてのエラーを明示的に処理するよりも改善されます。

15
JLRishe

Node.jsでは、次を使用できます。

process.on('unhandledRejection', (reason, promise) => {
  console.error(`Uncaught error in`, promise);
});
4
JussiR

ブラウザとNode.js環境の両方で実行できるコードを書いている場合、次のような自己実行機能でコードをラップできます。

var isNode = (typeof process !== 'undefined' && typeof process.on !== 'undefined');
(function(on, unhandledRejection) {
    // PUT ANY CODE HERE
    on(unhandledRejection, function(error, promise) {
        console.error(`Uncaught error in`, promise);
    });
    // PUT ANY CODE HERE
})(
    isNode ? process.on.bind(process) : window.addEventListener.bind(window),
    isNode ? "unhandledRejection" : "unhandledrejection"
);

このコードを使用するとどうなりますか:

  • Node.js環境で実行する場合、ハンドラーはプロセスオブジェクトにアタッチされ、プロミスにキャッチされない例外があるときに実行されます。

  • ブラウザー環境で実行する場合、ハンドラーはウィンドウオブジェクトにアタッチされ、promiseでキャッチされない例外があり、ブラウザーがunhandledrejectionイベントをサポートするときに実行されます。

  • unhandledrejectionをサポートしないブラウザー環境で実行すると、キャッチされない例外をキャッチできず、unhandledrejectionイベントハンドラーがトリガーされることはありませんが、キャッチされない例外がない場合のエラー。

2
John Slegers

ネイティブPromiseを使用している場合、それは非常に簡単です。
必要なのは.catchだけです。これはどこかを拒否します。

ajax(request).catch(function(rejected){
      console.log(rejected);
});

どこかで捕まえなければ、約束のつかまえられないものが現れ続けるでしょう。しかし、どこかで捕まえたら...

1
redyyu