スキルレベルに関係なく、エラーまたは例外はアプリケーション開発者の生活の一部です。 Web開発の矛盾は、エラーが発生した可能性のある多くの場所を残しています。ソリューションの鍵は、ユーザーのエクスペリエンスを制御するために、予期せぬ(または予見可能なエラー)に対処することです。 JavaScriptを使用すると、問題を正しく解決するために使用できるさまざまな技術的および言語機能があります。
JavaScriptのエラーを処理することは危険です。あなたがマーフィーの法律を信じているなら、何が間違っているかは最終的にうまくいかないでしょう!この記事では、JavaScriptでエラー処理を掘り下げます。私はいくつかの落とし穴と良い慣行を伴います。最後に、非同期コード処理とAJAXについて説明します。
JavaScriptのイベント駆動型モデルは、この言語に豊かな意味を追加すると思います。イベント駆動型エンジンと、この種のブラウザのエラー報告メカニズムに違いはないと思います。エラーが発生するたびに、特定の時点でイベントを投げることに相当します。理論的には、通常のイベントを処理するように、JavaScriptのエラースローイベントを処理できます。これがあなたに奇妙に聞こえるなら、以下の旅を始めることに集中してください。この記事では、クライアントのJavaScriptのみをターゲットにしています。
例
この記事で使用されているコードの例は、GitHubで取得できます。現在のページは次のようになります:
各ボタンをクリックすると、エラーが発生します。タイプエラータイプの例外をシミュレートします。以下は、このようなモジュールの定義と単体テストです。
function error(){var foo = {}; foo.bar();}を返しますまず、この関数は空のオブジェクトfooを定義します。 bar()メソッドはどこにも定義されていないことに注意してください。ユニットテストを使用して、これがエラーが発生することを確認します。
it( 'typeerror'、function(){deffer.throws(target、typeerror);});このユニットテストでは、MochaおよびShould.jsライブラリからのテストアサーションを使用します。 Mochaは実行中のテストフレームワークであり、should.jsはアサーションライブラリです。あなたがそれらにあまり慣れていないなら、あなたは彼らの文書をオンラインで無料で閲覧することができます。テストケースは通常、それから始まり(「説明」)、容疑または断りのアサーションの失敗で終わります。このフレームワークを使用することの利点は、ブラウザではなくノードでユニットテストできることです。 JavaScriptの多くの重要な基本概念を検証するため、これらのテストを真剣に受け止めることをお勧めします。
上記のように、ERROR()は空のオブジェクトを定義し、そのメソッドを呼び出そうとします。このオブジェクトにはbar()メソッドが存在しないため、例外がスローされます。 JavaScriptのような動的言語で私を信じてください。誰でもそのような間違いを犯すことができます。
悪いデモンストレーション
不十分なエラー処理方法を見てみましょう。間違ったアクションを抽象化し、ボタンにバインドします。これがハンドラーのユニットテストがどのように見えるかです:
function badhandler(fn){try {return fn(); } catch(e){} return null;}この処理関数は、依存関係としてコールバック関数FNを受信します。次に、機能はハンドラー内で呼び出されます。このユニットテストは、この方法の使用方法を例にとっています。
it( 'エラーなしで値を返します'、function(){var fn = function(){return 1;}; var result = target(fn);result。phould.equal(1);}); it( 'nullをエラーで返す'、function(){var fn = function(){shrow error ');} (結果).equal(null);});ご覧のとおり、エラーが発生した場合、この奇妙な処理方法はヌルを返します。このコールバック関数fn()は、法的方法またはエラーを指します。以下のクリック処理イベントは、残りを完成させます。
(function(handler、bomb){var badbutton = document.getElementbyId( 'bad'); if(badbutton){badbutton.addeventlistener( 'click'、function(){handler(){handler(){handler(bomb); console.log( '想像、想像、想像、想像して、ハイディングミス');};}悪いことは、私がちょうど得たのはヌルだったということです。これは、何が間違っているかを判断することを考えていたときに非常に混乱しました。エラーが発生したときのこの沈黙の戦略は、ユーザーエクスペリエンスデザインからデータの腐敗へのすべてのリンクをカバーします。その後のイライラする側面は、私がデバッグに時間を費やさなければならなかったが、トライキャッチコードブロックにエラーが表示されなかったということでした。この奇妙な処理は、コード内のすべてのエラーを隠し、すべてが正常であると仮定します。これは、コードの品質に注意を払わない一部のチームでスムーズに実行できます。ただし、これらの隠されたエラーにより、最終的にはコードのデバッグに時間を費やすことができます。コールスタックに依存する多層ソリューションでは、エラーがどこから来るのかを判断することができます。まれにトライキャッチを静かに処理することが適切かもしれません。しかし、エラーが発生した場合、それに対処しますが、これは良い解決策ではありません。
この失敗 - 沈黙戦略は、コードのエラーをよりよく処理するように促します。 JavaScriptは、このタイプの問題に対処するためのよりエレガントな方法を提供します。
読み取れないソリューション
続けて、理解しにくいアプローチを見てみましょう。しっかりと結合した部分をDOMとスキップします。この部分は、私たちが今見た悪いアプローチと違いはありません。焦点は、例外を処理する以下の単体テストの部分にあります。
function uglyhandler(fn){try {return fn(); } catch(e){スローエラー( '新しいエラー'); }} it( 'エラーを使用して新しいエラーを返します'、function(){var fn = function(){throw new TypeError( 'Type Error');}; should.throws(function(){ターゲット(fn);}、error);});今、悪い治療に比べて良い改善があります。例外はコールスタックにスローされます。私が好きなのは、エラーがスタックから解放されていることです。これは、デバッグに非常に役立ちます。例外がスローされると、通訳者はコールスタックのレベルで次の処理関数を調べます。これにより、コールスタックの上位レベルでエラーを処理する多くの機会が提供されます。残念ながら、彼は難しい間違いなので、元のエラー情報が表示されません。そのため、コールスタックに沿って見て、最も原始的な例外を見つけなければなりません。しかし、少なくとも、例外がスローされる場合にエラーが発生していることはわかっています。
この読めないエラー処理は無害ですが、コードを理解するのが難しくなります。ブラウザがエラーをどのように処理するかを見てみましょう。
スタックを呼び出します
次に、例外をスローする1つの方法は、トライを追加することです...コールスタックのトップレベルでコードブロックをキャッチします。例えば:
function main(bomb){try {bomb(); } catch(e){//すべてのエラーのものを処理}}しかし、ブラウザはイベント駆動型だと言ったことを覚えていますか?はい、JavaScriptの例外はイベントにすぎません。通訳は、例外が現在発生しているコンテキストでプログラムを停止し、例外をスローします。これを確認するために、以下は私たちが見ることができるグローバルなイベント処理機能onerrorです。このように見えます:
window.addeventlistener( 'error'、function(e){var error = e.error; console.log(error);});このイベントハンドラーは、実行環境でエラーをキャッチします。エラーイベントは、さまざまな場所でさまざまなエラーを生成します。このアプローチのポイントは、コードのエラーを中央に処理することです。他のイベントと同様に、グローバルハンドラーを使用してさまざまなエラーを処理できます。これにより、固体(単一の責任、オープンクロップ、リスコフの置換、インターフェースの分離、依存関係の反転)の原則に従うと、単一の目標のみがエラー処理されます。いつでもエラー処理機能を登録できます。インタープリターはこれらの機能ループを実行します。このコードは、試してみることで満たされたステートメントから解放されます...キャッチとデバッグが簡単になります。このアプローチの鍵は、通常のJavaScriptイベントと同じように発生するエラーを処理することです。
これで、グローバル処理機能を備えたコールスタックを表示する方法があります。私たちはそれで何ができますか?結局のところ、コールスタックを使用する必要があります。
コールスタックを記録します
コールスタックは、バグの修正を処理するのに非常に役立ちます。良いニュースは、ブラウザがこの情報を提供することです。エラーオブジェクトのスタック属性は現在標準ではありませんが、この属性は一般に新しいブラウザーでサポートされています。
だから、私たちにできるクールなことは、それをサーバーに印刷することです:
window.addeventlistener( 'error'、function(e){var stack = e.error.stack; var message = e.error.tostring(); if(stack){message + = '/n' + stack;} var xhr = new xmlhttprequest(); xhr.open( 'post'; '/log);コードの例では明らかではないかもしれませんが、このイベントハンドラーは以前のエラーコードによってトリガーされます。上記のように、各ハンドラーには単一の目的があり、コードを乾燥させます(ホイールを繰り返し作成せずに繰り返さないでください)。私が興味を持っているのは、サーバーでこれらのメッセージをキャプチャする方法です。
これがノードランタイムのスクリーンショットです:
コールスタックは、コードのデバッグに非常に役立ちます。コールスタックの役割を過小評価しないでください。
非同期処理
ああ、非同期コードを処理することは非常に危険です! JavaScriptは、現在の実行環境から非同期コードをもたらします。これは、トライに問題があることを意味します...以下の声明をキャッチします。
function asynchandler(fn){try {setimeout(function(){fn();}、1); } catch(e){}}この単体テストの残りの部分はまだあります。
It( 'エラーで例外をキャッチしません'、function(){var fn = function(){throw new typeerror( 'タイプエラー');}; failedpromise(){ターゲット(fn);})。 });}例外を確認することを約束して、このハンドラーを終了する必要があります。私のコードはすべて試していますが、キャッチされていますが、未処理の例外がまだ表示されていることに注意してください。はい、試してみてください...キャッチは別の実行環境でのみ動作します。例外がスローされると、通訳者の実行環境は現在のトライキャッチブロックではなくなります。この動作は、AJAXコールと同様に発生します。したがって、今では2つのオプションがあります。別の方法は、非同期コールバックで例外をキャッチすることです。
settimeout(function(){try {fn();} catch(e){//この非同期エラー}}、1);この方法は有用ですが、改善の余地はまだたくさんあります。まず、コードのキャッチブロックがコードのいたるところに表示されます。実際、1970年代のプログラミングコールでは、コードが後退したかったのです。さらに、V8エンジンは、TRYの使用を阻止します。機能でコードブロックをキャッチします(V8は、Chromeブラウザーとノードが使用するJavaScriptエンジンです)。彼らは、コールスタックの上部に例外をキャッチするこれらのコードブロックを書くことを推奨しています。
それで、これは私たちに何を教えてくれますか?上で言ったように、実行コンテキストのグローバルエラーハンドラーが必要です。ウィンドウオブジェクトにエラーハンドラーを追加すると、完了です!乾燥して堅実な原則に従うのはいいことではありませんか?グローバルなエラーハンドラーは、コードを読みやすくクリーンに保ちます。
以下は、サーバー側の例外処理に印刷されたレポートです。例でコードを使用する場合、使用しているブラウザによって出力がわずかに異なる場合があることに注意してください。
このハンドラーは、非同期コードからどのエラーが発生しているかを教えてくれます。エラーはsettimeout()ハンドラーからのエラーが発生していることがわかります。とてもかっこいい!
エラーはすべてのアプリケーションの一部ですが、適切なエラー処理はそうではありません。エラーに対処するには、少なくとも2つの方法があります。 1つは、失敗、沈黙の解決策です。つまり、コードのエラーを無視します。別の方法は、エラーを迅速に検出して解決すること、つまりエラーを停止して再現することです。私は自分が好きなものとなぜ私がそれが好きなのかをはっきりと表現したと思います。私の選択:問題を隠さないでください。あなたのプログラムでの予期せぬイベントについて誰もあなたを責めることはありません。これは、ポイントを破り、再現し、ユーザーに試してみることができます。不完全な世界では、自分にチャンスを与えることが重要です。エラーは避けられません。あなたがすることは、エラーを解決するために重要です。 JavaScriptのエラー処理機能と自動で柔軟なデコードの合理的な使用により、ユーザーのエクスペリエンスがよりスムーズになり、開発者の診断が簡単になります。