JavaScriptエラーをキャプチャして分析する方法
フロントエンドエンジニアは皆、JavaScriptに基本的な例外処理機能があることを知っています。新しいエラー()をスローできます。また、APIエラーを呼び出すと、ブラウザも例外をスローします。しかし、ほとんどのフロントエンドエンジニアは、これらの例外的な情報を収集することを検討していないと推定されています。とにかく、JavaScriptエラーの後に更新が再現できない限り、ユーザーはリフレッシュして問題を解決でき、ブラウザはクラッシュしません。この仮定は、シングルページアプリが人気になる前に当てはまりました。現在のシングルページアプリは、一定期間実行された後、いくつかの入力操作を実行した可能性があります。以前の操作を完全に作り直しませんか?そのため、これらの例外情報をキャプチャして分析する必要があります。その後、ユーザーエクスペリエンスに影響を与えないようにコードを変更できます。
例外をキャッチする方法
私たちは自分自身を書き留めました()、私たちはそれをキャプチャしたいと思います。ただし、ブラウザAPIを呼び出すときに発生する例外は、必ずしも標準に例外がスローされると言っています。前者の場合は、トライキャッチでそれをキャッチすることもできます。後者は、グローバルな例外を聴き、それをキャッチする必要があります。
トライキャッチ
一部のブラウザAPIが例外をスローすることが知られている場合、エラーのためにプログラム全体が違法状態に入ることを避けるために、トライキャッチにコールを配置する必要があります。たとえば、window.localStorageはこのようなAPIです。
コードコピーは次のとおりです。
試す {
localStorage.setItem( 'date'、date.now());
} catch(error){
ReporterRor(エラー);
}
もう1つの一般的なトライキャッチ適用シナリオは、コールバックです。コールバック関数のコードは制御できないため、コードがどれほど優れているか、そして例外をスローする他のAPIが呼び出されるかどうかはわかりません。コールバックエラーのためにコールバックを呼び出した後に他のコードを実行しないようにするために、コールをトライキャッチに戻す必要があります。
コードコピーは次のとおりです。
listens.foreach(function(ristener){
試す {
リスナー();
} catch(error){
ReporterRor(エラー);
}
});
window.onerror
Try-Catchがカバーできない場所の場合、例外が発生した場合、Window.onerrorを介してのみキャプチャできます。
コードコピーは次のとおりです。
window.onerror =
関数(errormessage、scripturi、linenumber){
ReporterRor({
メッセージ:ErrorMessage、
スクリプト:Scripturi、
ライン:LinEnumber
});
}
賢くないように注意して、window.addeventlistenerまたはwindow.attacheventを使用して、window.onerrorを聴きます。多くのブラウザは、Window.onerrorのみを実装するか、Window.onerrorの実装のみを実装しています。標準ドラフトがWindow.onerrorも定義することを考慮すると、window.onerrorを使用する必要があります。
不動産がありません
キャッチされた例外を収集してから、クエリと分析のためにサーバー側のストレージにバッチでそれらを送信するレポーターター機能があるとしましょう。どの情報を収集したいですか?より便利な情報には、エラータイプ(名前)、エラーメッセージ(メッセージ)、スクリプトファイルアドレス(スクリプト)、行番号(行)、列番号(列)、およびスタックトレースが含まれます。 Try-Catchで例外がキャッチされている場合、これらの情報はすべてエラーオブジェクト(主流のブラウザでサポートされている)にあります。そのため、ReporterRorもこの情報を収集できます。しかし、Window.onerrorを介してキャプチャされた場合、このイベント関数には3つのパラメーターしかないことがわかっているため、これら3つのパラメーター以外の情報が失われます。
メッセージをシリアル化します
エラーオブジェクトが自分で作成された場合、エラー。メッサージは私たちによって制御されます。基本的に、Error.messageに入れたもの、およびWindow.onerrorの最初のパラメーター(メッセージ)となるもの。 (ブラウザは実際に「有名なエラー:」プレフィックスを追加するなど、少し変更します。 window.onerrorでそれらを取り出して、それをゆるくするだけです。もちろん、これは自分で作成したエラーオブジェクトに限定されます。
5番目のパラメーター
ブラウザメーカーは、Window.onerrorを使用するときに人々が対象となる制限も知っているため、Window.onerrorに新しいパラメーターの追加を開始します。行番号と列番号のみが非常に対称的でないように見えることを考慮すると、最初に列番号を追加して4番目のパラメーターに配置しました。しかし、誰もがより心配しているのは、完全なスタックを取得できるかどうかということです。そのため、Firefoxは、スタックを5番目のパラメーターに配置する方が良いと言いました。しかし、Chromeは、エラーオブジェクト全体を5番目のパラメーターに配置する方が良いと述べました。その結果、Chromeがより速くなるため、Chrome 30に新しいwindow.onerror署名が実装されたため、標準ドラフトの次の記述が実装されました。
コードコピーは次のとおりです。
window.onerror = function(
誤り、
scripturi、
linenumber、
columnnumber、
エラー
){
if(error){
ReporterRor(エラー);
} それ以外 {
ReporterRor({
メッセージ:ErrorMessage、
スクリプト:Scripturi、
ライン:linenumber、
列:columnNumber
});
}
}
属性の規則性
以前に説明したエラーオブジェクトプロパティの名前は、クロムネーミングメソッドに基づいています。したがって、エラーオブジェクト、つまり、異なる属性名を統一属性名にマッピングするための特別な関数も必要です。特定のプラクティスについては、この記事を参照してください。ブラウザの実装は更新されますが、人間がそのようなマッピングテーブルを維持することはそれほど難しくありません。
Stack Trace形式も同様です。このプロパティは、各ブラウザで使用されるテキスト形式が異なるため、例外のスタック情報を保存します。 。
セキュリティの制限
「スクリプトエラー」というメッセージでエラーが発生した場合、私が話していることを理解できます。これは、実際にはさまざまなソースからのスクリプトファイルに対するブラウザの制限です。このセキュリティ制限の理由は次のとおりです。ログイン後にオンライン銀行家によって返されたHTMLが匿名のユーザーが見たHTMLとは異なると仮定します。サードパーティのWebサイトは、このオンラインバンクのURIをスクリプトに入れることができます。 SRC属性。もちろん、HTMLはJSとして解析できないため、ブラウザは例外をスローし、このサードパーティのWebサイトは、例外の場所を分析することでユーザーがログインするかどうかを判断できます。このため、ブラウザはさまざまなソーススクリプトファイルによってスローされるすべての例外をフィルタリングし、「スクリプトエラー」のような変更されていないメッセージのみを残し、他のすべての属性が消えます。
特定のスケールのWebサイトの場合、スクリプトファイルをCDNに配置することが正常であり、さまざまなソースが配置されます。自分で小さなWebサイトを構築したとしても、jQueryやBackboneなどの一般的なフレームワークは、ユーザーのダウンロードをスピードアップするために、パブリックCDNのバージョンを直接参照できます。したがって、このセキュリティ制限はいくつかの問題を引き起こし、ChromeとFirefoxから収集した例外情報を役に立たない「スクリプトエラー」にします。
cors
この制限をバイパスする場合は、スクリプトファイルとページ自体が同じであることを確認してください。しかし、CDNによって加速されていないサーバーにスクリプトファイルを配置すると、ユーザーのダウンロード速度が低下しませんか?解決策の1つは、スクリプトファイルをCDNに配置し続け、XMLHTTPREQUESTを使用してCORSを介してコンテンツをダウンロードし、<script>タグを作成してページに挿入することです。ページに埋め込まれたコードは、もちろん同じ起源です。
これは簡単ですが、実装する詳細はたくさんあります。簡単な例を示すには:
コードコピーは次のとおりです。
<スクリプトsrc = "http://cdn.com/step1.js"> </script>
<スクリプト>
(function step2(){})();
</script>
<スクリプトsrc = "http://cdn.com/step3.js"> </script>
Step1、Step2、およびStep3に依存関係がある場合、この順序で厳密に実行する必要があることを知っています。そうしないと、エラーが発生する可能性があります。ブラウザはSTEP1およびSTEP3ファイルを並行して要求できますが、実行すると注文が保証されます。 xmlhttpRequestを使用してSTEP1およびSTEP3のファイルの内容を取得する場合、自分で正しい順序を確保する必要があります。さらに、ステップ2が非ブロッキングフォームでダウンロードされたときにステップ2を実行できます。また、ステップ2に干渉し、実行する前にステップ1が完了するのを待たせる必要があります。
ウェブサイト上のさまざまなページの<script>タグを生成するための完全なツールセットが既にある場合は、<script>タグに変更を加えるためにこのツールセットを調整する必要があります。
コードコピーは次のとおりです。
<スクリプト>
SchedulerEmotescript( 'http://cdn.com/step1.js');
</script>
<スクリプト>
scheduleinlinescript(function code(){
(function step2(){})();
});
</script>
<スクリプト>
SchedulerEmotescript( 'http://cdn.com/step3.js');
</script>
2つの関数scheduleremotescriptとscheduleInlinescriptを実装し、外部スクリプトファイルを参照し、残りの<script>タグが上記のフォームに書き換えられる最初の<script>タグの前に定義されることを確認する必要があります。すぐに実行されたstep2関数は、より大きなコード関数に配置されたことに注意してください。コード関数は実行されず、単なるコンテナであるため、元のStep2コードを逃げることなく保持できますが、すぐには実行されません。
次に、アドレスに基づいてSchedulerEmotescriptによってダウンロードされたファイルコンテンツと、ScheduleInlinescriptで直接取得したコードを正しい順序で1つずつ実行できるようにするために、完全なメカニズムを実装する必要があります。ここで詳細なコードは提供しません。
ライン番号チェック
CORSを介してコンテンツを取得し、ページにコードを注入すると、セキュリティの制限が突破される可能性がありますが、新しい問題、つまりライン番号の競合が導入されます。もともと、一意のスクリプトファイルはerror.scriptを介して配置でき、その後、一意の行番号はerror.lineから配置できます。これで、それらはすべてページに埋め込まれているため、複数の<script>タグはerror.scriptで区別できません。 。
行数の競合を回避するために、各<script>タグの実際のコードで使用される線番号間隔が互いに重複しないように、いくつかの行番号を無駄にすることができます。たとえば、各<script>タグの実際のコードが1000行を超えないと仮定すると、最初の<script>タグのコードを行11000を取り上げ、2番目の<script>タグを作成して、コードのコードを占領します。 10012000(挿入前に1000の空の線が挿入された)、3番目の<script>タグのコードは20013000を占める(2000の空の行が挿入される前に挿入された)など。次に、データ - *属性を使用して、簡単なバックチェックのためにこの情報を記録します。
コードコピーは次のとおりです。
<スクリプト
data-src = "http://cdn.com/step1.js"
data-line-start = "1"
>
//ステップ1のコード
</script>
<Script data-line-start = "1001">
// '/n' * 1000
//ステップ2のコード
</script>
<スクリプト
data-src = "http://cdn.com/step3.js"
data-line-start = "2001"
>
// '/n' * 2000
//ステップ3のコード
</script>
この処理後、エラーエラーが3005の場合、実際のエラー.scriptが「http://cdn.com/step3.js」である必要がありますが、実際のエラーは5でなければなりません。前述の記者機能でこのライン番号の逆チェックを完了することができます。
もちろん、各スクリプトファイルには1000行しかないことを保証することはできないため、一部のスクリプトファイルが1000行未満である可能性もあるため、各<スクリプト>タグに1000行間隔を正しく割り当てる必要はありません。スクリプト行の実際の数に基づいて間隔を割り当てることができます。各<script>タグで使用される間隔が重複しないことを確認してください。
クロスリギン属性
さまざまなソースからのコンテンツにブラウザによって課されるセキュリティ制限は、もちろん<script>タグに限定されません。 XmlhttpRequestはCORSを介してこの制限を突破できるため、タグを許可されていないリソースが直接参照されるのはなぜですか?これは確かに大丈夫です。
<img>タグの異なるソース画像ファイルを参照することには、<script>タグの異なるソーススクリプトファイルを参照することの制限も適用されます。 <img>タグが別のソースである場合、<canvas>図面で使用されると、<canvas>は書き込みのみの状態になり、WebサイトがJavaScriptを介して異なるソースから不正な画像データを盗むことができないようにします。その後、<img>タグは、クロスリギン属性を導入することにより、この問題を解決しました。 Crossorigin = "Anonymous"の場合、それは匿名のCORSに相当します。
<img>タグはこれを行うことができるので、<script>タグがこれを行うことができないのはなぜですか?そのため、ブラウザメーカーは、上記のセキュリティ制限を解決するために、<script>タグに同じCrossorigin属性を追加しました。現在、このプロパティのChromeとFirefoxのサポートは完全に無料です。 SafariはCrossorigin = "Anonymous"をCrossorigin = "use-credentials"として扱います。その結果、サーバーが匿名のcorsのみをサポートしている場合、Safariは認証を障害として扱います。 CDNサーバーは、パフォーマンス上の理由で静的コンテンツのみを返すように設計されているため、リクエストに基づいてCORSを認証するために必要なHTTPヘッダーを動的に返すことは不可能です。
要約します
JavaScriptの例外処理はシンプルに見え、他の言語と違いはありませんが、すべての例外をキャッチしてプロパティを分析するのはそれほど簡単ではありません。一部のサードパーティサービスは現在、JavaScriptの例外をキャッチするGoogle Analyticsサービスを提供していますが、詳細と原則を理解したい場合は、自分でやらなければなりません。