フロントエンドエンジニアは皆、JavaScriptに基本的な例外処理機能があることを知っています。新しいエラー()をスローできます。また、APIエラーを呼び出すと、ブラウザも例外をスローします。しかし、ほとんどのフロントエンドエンジニアがこれらの例外情報を収集することを検討したことがないと推定されています
とにかく、JavaScriptエラーの後に更新が再現できない限り、ユーザーはリフレッシュして問題を解決でき、ブラウザはクラッシュしません。この仮定は、シングルページアプリが人気になる前に当てはまりました。現在のシングルページアプリは、一定期間実行された後、非常に複雑です。ユーザーは、ここに来る前にいくつかの入力操作を実行した可能性があります。彼らが望んでいると言うなら、彼らはどのようにリフレッシュできますか?以前の操作を完全に作り直しませんか?そのため、これらの例外情報をキャプチャして分析する必要があります。その後、ユーザーエクスペリエンスに影響を与えないようにコードを変更できます。
例外をキャッチする方法
新しいエラー()をスローすることを書きました。キャプチャしたい場合は、スローが書かれている場所を非常によく知っているので、確かにキャプチャできます。ただし、ブラウザAPIを呼び出すときに発生する例外は、必ずしもキャッチしやすいわけではありません。一部のAPIによると、例外は標準にスローされ、一部のAPIには、実装の違いまたは欠陥のために個々のブラウザのみが例外をスローすると言います。前者の場合は、トライキャッチでそれをキャッチすることもできます。後者は、グローバルな例外を聴き、それをキャッチする必要があります。
トライキャッチ
一部のブラウザAPIが例外をスローすることが知られている場合、エラーのためにプログラム全体が違法状態に入ることを避けるために、トライキャッチにコールを配置する必要があります。たとえば、window.localStorageはそのようなAPIです。データを作成した後に容量制限を超えた後に例外がスローされ、これはSafariのプライベートブラウジングモードでも当てはまります。
コードコピーは次のとおりです。
試す {
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の最初のパラメーター(メッセージ)となるもの。 (ブラウザは、「congaughtエラー:」プレフィックスを追加するなど、実際にはわずかに変更されます。したがって、心配している属性(json.stringifyなど)をシリアル化し、それらを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
});
}
}
属性の規則性
以前に説明したエラーオブジェクトプロパティの名前は、Chromeネーミング方法に基づいています。ただし、異なるブラウザはエラーオブジェクトのプロパティに異なります。たとえば、スクリプトファイルアドレスはChromeのスクリプトと呼ばれますが、Firefoxではファイル名です。したがって、エラーオブジェクト、つまり、異なる属性名を統一属性名にマッピングするための特別な関数も必要です。特定のプラクティスについては、この記事を参照してください。ブラウザの実装は更新されますが、人間がそのようなマッピングテーブルを維持することはそれほど難しくありません。
Stack Trace形式も同様です。このプロパティは、例外がプレーンテキストで発生したときにスタック情報を保存します。各ブラウザで使用されるテキスト形式は異なるため、各フレームの関数名(識別子)、ファイル(識別子)、行番号(行)、列(列)を抽出するために正規式を維持する必要もあります。
セキュリティの制限
「スクリプトエラー」というメッセージでエラーが発生した場合、私が話していることを理解できます。これは、実際にはさまざまなソースからのスクリプトファイルに対するブラウザの制限です。このセキュリティ制限の理由は次のとおりです。ログイン後にオンライン銀行家によって返されたHTMLが匿名のユーザーが見たHTMLとは異なると仮定します。サードパーティのWebサイトは、このオンラインバンクのURIをScript.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は、ステップ1が非ブロッキングフォームでダウンロードされたときに実行できます。そのため、ステップ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で区別できません。ただし、各<スクリプト>タグ内の行番号は1から計算されるため、例外情報を使用してエラーが配置されているソースコードの場所を見つけることができません。
行数の競合を回避するために、各<script>タグの実際のコードで使用される線番号間隔が互いに重複しないように、いくつかの行番号を無駄にすることができます。たとえば、各<script>タグの実際のコードが1000行を超えないと仮定すると、最初の<script>タグを占領する行11000のコードを許可することができます。2番目の<script>タグを占領するコードは10012000(1000回の空の行が挿入されました)、3番目の<スクリプト>タグのコードは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と同等です。 Crossorigin = "use-credentials"の場合、それは認定されたCORSと同等です。
<img>タグはこれを行うことができるので、<script>タグがこれを行うことができないのはなぜですか?そのため、ブラウザメーカーは、上記のセキュリティ制限を解決するために、<script>タグに同じCrossorigin属性を追加しました。現在、このプロパティのChromeとFirefoxのサポートは完全に無料です。 SafariはCrossorigin = "Anonymous"をCrossorigin = "use-credentials"として扱います。その結果、サーバーが匿名のcorsのみをサポートしている場合、Safariは認証を障害として扱います。 CDNサーバーは、パフォーマンス上の理由で静的コンテンツのみを返すように設計されているため、リクエストに基づいてCORSを認証するために必要なHTTPヘッダーを動的に返すことは不可能です。 Safariは、この機能を使用して上記の問題を解決できないことと同等です。
要約します
JavaScriptの例外処理はシンプルに見え、他の言語と違いはありませんが、すべての例外をキャッチしてプロパティを分析するのはそれほど簡単ではありません。現在、一部のサードパーティサービスは、JavaScriptの例外をキャッチするGoogleアナリティクスのようなサービスを提供していますが、詳細と原則を理解したい場合は、それでも自分でやらなければなりません。