JavaScript例外処理


82

JavaScript内でスローされたすべての例外をキャッチするための最良のテクニックは何ですか?

明らかに、最良のテクニックはtry ... catchを使用することです。ただし、非同期コールバックなどでは、注意が必要になる場合があります。

IEとGeckoのブラウザがwindow.onerrorをサポートしていることは知っていますが、OperaとSafariはどうですか?

これが私が中心的な例外処理ソリューションを持ちたいと思うたくさんのテストケースです:

// ErrorHandler-Test1
var test = null;
test.arg = 5;
// ErrorHandler-Test2
throw (new Error("Hello"));
// ErrorHandler-Test3
throw "Hello again";
// ErrorHandler-Test4
throw {
    myMessage: "stuff",
    customProperty: 5,
    anArray: [1, 2, 3]
};
// ErrorHandler-Test5
try {
    var test2 = null;
    test2.arg = 5;
} catch(e) {
    ErrorHandler.handleError(e);
}
// ErrorHandler-Test6
try {
    throw (new Error("Goodbye"));
} catch(e) {
    ErrorHandler.handleError(e);
}
// ErrorHandler-Test7
try {
    throw "Goodbye again";
} catch(e) {
    ErrorHandler.handleError(e);
}
// ErrorHandler-Test8
try {
    throw {
        myMessage: "stuff",
        customProperty: 5,
        anArray: [1, 2, 3]
    };
} catch(e) {
    ErrorHandler.handleError(e);
}

他のテストケースについて考えた場合は、それらについて言及してください。これらのケースのいくつかは、ErrorHandler.handleErrorメソッドに言及しています。これは、try ... catchを使用する際の推奨ガイドラインです。


私の答えに対するコメントに気づかなかったことが明らかであるという理由だけで、「しかし、OperaとSafariはどうですか?」という質問として読んだときに、「質問に記載されている」と私を否定したようです。私はここで提起された質問に具体的に答えました。WTF?
まぶたのない2008年

1
WebKitのでは、window.onerror行方不明は、以来、問題となっていた2003年、それはそれはだように見え、最終的に解決ばかり。もちろん、Operaは頑固なままです。
josh3736 2010年

参考までにwindow.onerrorは
-Firefox7.0.1-

11
なぜこれが閉鎖されたのかわからない。再開に投票しました。
ripper234 2012

1
同意しました、これは有用な質問です。私が考えることができるのはcasperOneだけです。これが代わりにある種のブラウザ戦争の議論になるのではないかと恐れていましたか?
ジョーダンライター2012年

回答:


23

すべてのイベントハンドラーを割り当てるためにjQueryのようなライブラリを使用する場合はwindow.onerror、jQueryイベントハンドラーコードとon ready関数を組み合わせて使用し、エラー処理関数を使用できますJavaScriptエラー追跡:window.onerrorが十分でない理由を参照)。)。

  • window.onerror:IEのすべてのエラー(およびFirefoxのほとんどのエラー)をキャッチしますが、SafariとOperaでは何もしません。
  • jQueryイベントハンドラー:すべてのブラウザーでjQueryイベントエラーをキャッチします。
  • jQuery ready関数:すべてのブラウザーで初期化エラーをキャッチします。

私はすでに解決策を提供していない記事を読んでいました。私はjQueryを使用していませんが、あなたが何を意味しているのか心配です。jQueryが例外を食べていると言っているのですか?!それとも、単にログ機能を提供するだけですか(これは私の元の質問に答えた後にのみ役立ちます)?
harley.333 2008年

jQueryは、例外に関して特別なことは何もしません。ただし、jQueryを使用してすべてのイベントを追加すると、私の回答の2番目のリンクで説明されているように、trycatchステートメントとエラー処理コードを追加するための単一の場所が提供されます。
カール

2
:リンクが移動してblogs.cozi.com/tech/2008/04/...
natacado

1
これはまだ本当ですか?onerrorSafari + Chromeで通常の処理方法を試したところ、正しく機能しているようです。
ジュリ

「それだけでは不十分」という理由へのリンクはかなり古い情報であり、現在はそうではありません。
vsync 2014年

21

WebKit(Safari、Chromeなど)がをサポートしているように見えますonerror

元の投稿:私が知る限り、WebKit / Safariはこのonerrorイベントをサポートしていません。これはとても残念です。


19
ええと、そうではありません。質問で尋ねられた:「しかし、OperaとSafariはどうですか?」
まぶたのない2008年

のように、私は質問の投稿で提起された質問に具体的に答えました。
まぶたのない2008年

8
彼は「[window.onerrorがない] OperaとSafariについて[どうするか]」という意味だったと思います。
nickf 2009年

10
@nickfかもしれませんが、もしそうなら、それは非常にひどい言い回しであり、私の解釈は最悪の場合理解可能であり、せいぜい最も可能性が高いです。特に質問がそれを 述べいないことを考えると、人々が私の答えを投票するのはかなり悪い理由であり、他の読者は肯定的または否定的な声明から利益を得るかもしれません
まぶたのない2011年

Chromeは現在それをサポートしているようです。
ダニエルXムーア

7

実際、jqueryのアプローチはそれほど悪くはありません。見る:

http://docs.jquery.com/Events/error#fn

そして:

$(window).error(function(msg, url, line){
  $.post("js_error_log.php", { msg: msg, url: url, line: line });
});

11
これを今見つけている人のために-jqueryは実際にはイベントをwindow.errorイベントにバインドしないことをお勧めします-上記のドキュメントリンクを参照してください。抽出:jQueryエラーイベントハンドラーをウィンドウオブジェクトにアタッチしないでください。[...]代わりにwindow.onerrorを使用してください。
zcrar70 2011年

多くの場合、このようにバインドされることは想定されていません。非論理的です。この入札が行われるまでに多くのエラーが発生する可能性があります(成功した場合でも...)
vsync 2014年

6

独自の例外ハンドラですべての例外をキャッチし、instanceofを使用します。

$("inuput").live({
    click : function (event) {
        try {
            if (somethingGoesWrong) {
                throw new MyException();
            }
        } catch (Exception) {
            new MyExceptionHandler(Exception);
        }

    }
});

function MyExceptionHandler(Exception) {
    if (Exception instanceof TypeError || 
        Exception instanceof ReferenceError || 
        Exception instanceof RangeError ||  
        Exception instanceof SyntaxError ||     
        Exception instanceof URIError ) {
        throw Exception; // native error
     } else {
         // handle exception
     }
}

try-catchブロックがないため、MyExcetpionHandlerはネイティブエラーをスローします。

訪問http://www.nczonline.net/blog/2009/03/10/the-art-of-throwing-javascript-errors-part-2/


4

try-catch常に最良の解決策であるとは限りません。たとえば、Chrome 7.0では、コンソールウィンドウの優れたスタックトレースが失われます。例外を再スローしても効果はありません。私はジャムがスタックトレースがすべてのソリューションを知らないあなたは例外に反応させます。


2

少しの作業で、すべてのブラウザで適度に完全なスタックトレースを取得することができます。

最新のChromeとOpera(つまり、Blinkレンダリングエンジンに基づくもの)は、ErrorEventとのHTML5ドラフト仕様を完全にサポートしていますwindow.onerror。これらのブラウザの両方で、を使用するかwindow.onerror、(驚くべきことに!) 'error'イベントに適切にバインドすることができます。

// Only Chrome & Opera pass the error object.
window.onerror = function (message, file, line, col, error) {
    console.log(message, "from", error.stack);
    // You can send data to your server
    // sendData(data);
};
// Only Chrome & Opera have an error attribute on the event.
window.addEventListener("error", function (e) {
    console.log(e.error.message, "from", e.error.stack);
    // You can send data to your server
    // sendData(data);
})

残念ながら、Firefox、Safari、IEはまだ存在しており、私たちもそれらをサポートする必要があります。スタックトレースはで利用できwindow.onerrorないため、もう少し作業を行う必要があります。

エラーからスタックトレースを取得するためにできることは、すべてのコードをtry{ }catch(e){ }ブロックにラップしてからe.stackを確認することだけであることがわかりました。関数を受け取り、適切なエラー処理で新しい関数を返すwrapという関数を使用すると、プロセスをいくらか簡単にすることができます。

function wrap(func) {
    // Ensure we only wrap the function once.
    if (!func._wrapped) {
        func._wrapped = function () {
            try{
                func.apply(this, arguments);
            } catch(e) {
                console.log(e.message, "from", e.stack);
                // You can send data to your server
                // sendData(data);
                throw e;
            }
        }
    }
    return func._wrapped;
};

これは機能します。手動でラップする関数はすべて、適切なエラー処理が行われます。

次のように画像タグを使用してデータを送信できます

function sendData(data) {
    var img = newImage(),
        src = http://yourserver.com/jserror + '&data=' + encodeURIComponent(JSON.stringify(data));

    img.crossOrigin = 'anonymous';
    img.onload = function success() {
        console.log('success', data);
    };
    img.onerror = img.onabort = function failure() {
        console.error('failure', data);
    };
    img.src = src;
}

ただし、データを収集するにはバックエンドを実行し、データを視覚化するにはフロントエンドを実行する必要があります。

Atatus、我々はこの問題の解決に取り組んでいます。Atatusは、エラートラッキングだけでなく、実際のユーザーモニタリングを提供します。

https://www.atatus.com/をお試しください

免責事項:私はAtatusのWeb開発者です。


1

確かに、最近のブラウザーでは、Ajaxエラー用のjQueryイベントハンドラーを追加するとともに、ウィンドウを一番上までバブルするエラーに対してwindow.onerrorをフックすると、クライアントコードでスローされた実質的にすべてのエラーオブジェクトがキャッチされます。window.onerrorのハンドラーを手動で設定している場合、最近のブラウザーではこれはで行われwindow.addEventListener('error', callback)ますが、IE8 / 9ではを呼び出す必要があります window.attachEvent('onerror', callback)

次に、これらのエラーが処理されている環境と、その理由を検討する必要があることに注意してください。スタックトレースでできるだけ多くのエラーをキャッチすることは1つのことですが、最新のF12開発ツールの出現により、ローカルで実装およびデバッグするときにこのユースケースが解決されます。ブレークポイントなどは、ハンドラーから利用できるよりも多くのデータを提供します。特に、CORSリクエストからロードされたサードパーティライブラリによってスローされたエラーの場合はそうです。このデータを提供するようにブラウザに指示するには、追加の手順を実行する必要があります。

重要な問題は、このデータを本番環境で提供することです。ユーザーは、テストできるよりもはるかに幅広いブラウザーとバージョンを実行することが保証されており、QAをいくら投げても、サイト/アプリが予期しない方法で破損するためです。それ。

これを処理するには、ユーザーがコードを使用するときにユーザーのブラウザーでスローされたすべてのエラーを取得し、エンドポイントに送信してデータを表示し、発生したバグを修正するために使用できる本番エラートラッカーが必要です。 。Raygun(免責事項:私はRaygunで働いています)では、ナイーブな実装では見逃されると考えられる落とし穴や問題がたくさんあるため、これに優れたエクスペリエンスを提供するために多大な努力を払ってきました。

たとえば、JSアセットをバンドルして縮小する可能性があります。つまり、縮小されたコードからスローされたエラーには、変数名が壊れたジャンクスタックトレースが含まれます。このためには、ソースマップを生成するビルドツール(パイプラインのこの部分にはUglifyJS2をお勧めします)と、これらを受け入れて処理し、マングルされたスタックトレースを人間が読める形式に戻すエラートラッカーが必要です。Raygunはこれらすべてをすぐに実行でき、ビルドプロセスによって生成されたソースマップを受け入れるためのAPIエンドポイントが含まれています。非公開にする必要があるため、これが重要です。非公開にしないと、誰もがコードを縮小せず、その目的を否定する可能性があります。

raygun4jsのクライアントライブラリも付属していますwindow.onerrorjQueryのは、アウト・オブ・ボックスのフックとしてのみ追加する必要があるので、あなた次第これを設定するだけでなく、両方の現代とレガシーブラウザ用:

<script type="text/javascript" src="//cdn.raygun.io/raygun4js/raygun.min.js" </script> <script> Raygun.init('yourApiKey').attach(); </script>

送信前にエラーペイロードを変更する機能、タグとカスタムデータの追加、エラーを見たユーザーのメタデータなど、多数の機能が組み込まれています。また、前述のサードパーティのCORSスクリプトから適切なスタックトレースを取得する手間を省き、恐ろしい「スクリプトエラー」(エラーメッセージやスタックトレースを含まない)を解決します。

より重大な問題は、Web上の膨大な数のオーディエンスのために、サイトが各エラーの何千もの重複インスタンスを生成することです。Raygunのようなエラー追跡サービスには、これらをエラーグループにまとめるスマート機能があり、大量の通知に溺れることはなく、実際の各エラーを修正する準備ができていることを確認できます。


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