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