[107] [[Web]] において[[スクリプト]]の[[エラー]]は、 [DFN[[CODE(DOMe)@en[[[error]]]]]] [[イベント]]として通知されます。この[[イベント]]が所定の手順で処理されない場合、 [[利用者]]に通知されます。 * 仕様書 [REFS[ - [13] '''[CITE@en-US-x-hixie[HTML Standard]] ([TIME[2014-04-03 03:44:44 +09:00]] 版) ''' - [48] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2014-04-03 03:44:44 +09:00]] 版) - [49] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2014-04-03 03:44:44 +09:00]] 版) - [51] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2014-04-03 03:44:44 +09:00]] 版) - [55] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2014-04-03 03:44:44 +09:00]] 版) - [61] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2014-04-03 03:44:44 +09:00]] 版) - [64] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2014-04-03 03:44:44 +09:00]] 版) - [75] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2014-04-03 03:44:44 +09:00]] 版) - [93] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2014-04-03 03:44:44 +09:00]] 版) - [91] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2014-04-03 03:44:44 +09:00]] 版) - [90] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2014-04-03 03:44:44 +09:00]] 版) - [92] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2014-04-03 03:44:44 +09:00]] 版) - [106] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2014-04-03 03:44:44 +09:00]] 版) ]REFS] * エラーの処理 [108] [[スクリプト]]の構文解析の失敗や[[スクリプト]]内で[[例外]]が投げられてそれが [[catch]] されない場合など、[[スクリプト]]の処理中に検出され[[スクリプト]]内で直接処理されなかった失敗が本項でいう[[エラー]]です。 [109] [[エラー]]はまず[[エラーの報告]]手順に引き渡されて、 [[エラー]]を処理するために事前に登録された[[スクリプト]]によって扱おうとします。 [110] そのような[[スクリプト]]が存在しない場合や、処理できないとされる場合、 エラー処理中にエラーが発生した場合には、このエラーを[[利用者]]に報告することができます。 [57] 仕様書上の手順としてエラーがどのように処理されるかは、 エラーが静的 ([[構文解析]]、[[コンパイル]]等で検出されるエラー) か動的 (実行時エラー、 [[catch]] されない[[例外]]など) か、[[スクリプト]]が仕様書上どのように定義されているかによって異なります。 [58] [[スクリプトの作成]]手順によって作られる[[スクリプト]] (ほとんどの[[スクリプト]]) の静的エラーについては、 [[スクリプトの作成]]手順から[[エラーの報告]]手順が呼び出されます。 ([[スクリプトの作成]]の項を参照。) [59] [[イベントハンドラー]]の静的エラーについては、 [[get the current value of the event handler]] 手順から[[エラーの報告]]手順が呼び出されます。 ([[イベントハンドラー]]の項を参照。) ;; [41] [[エラー]]が[[取り扱われなかった]]場合、呼び出し元である >>58, >>59 から[[利用者]]に[[エラー]]が報告して[['''構わない''']]とされています。 [62] [CODE(DOMi)@en[[[Document]]]] と関連付けられた[[スクリプト]]で [[catch]] されていない実行時エラーが発生した時は、 その[[スクリプト]]の[[設定オブジェクト]]の[[大域スクリプト]]を[[対象]]として[[エラーを報告]]しなければ[['''なりません''']]。 それによって[[エラー]]が[[取り扱われなかった]]場合は、[[利用者]]に報告して[['''構いません''']]。 [SRC[>>61]] ;; [63] [CODE(DOMi)@en[[[Document]]]] と関連付けられた[[スクリプト]]というのが曖昧ですが、 [[ワーカー]]ではなく[[閲覧文脈]]内で実行されている[[スクリプト]]のことを指していると思われます。 [60] [[ワーカー]]の静的エラーについては、 [[run a worker]] 手順により、[[実行時エラー]]と同じように処理されることになっています。 [76] [[ワーカー]]のスクリプトで [[catch]] されていないエラーが発生した時は、 [CODE(DOMi)@en[[[WorkerGlobalScope]]]] を[[対象]]として[[エラーを報告]]しなければ[['''なりません''']]。 それによって[[エラー]]が[[取り扱われなかった]]場合は、次のようにします。 [SRC[>>75]] [FIG[ - [77] [[共有ワーカー]]の場合は、[[利用者]]に報告して[['''構いません''']]。 [SRC[>>76]] - [78] [[専用ワーカー]]の場合は、次のような[[タスク]]を[[DOM操作タスク源]]で[[キュー]]に追加します。 -= [79] [[ワーカー]]に関連付けられた [CODE(DOMi)@en[[[Worker]]]] [[オブジェクト]]において [CODE(DOMi)@en[[[ErrorEvent]]]] を[[発火]]します。 --- [80] [[trusted]] とします。 --- [81] [[イベント型]]は [CODE(DOMe)@en[[[error]]]] とします。 --- [82] [[bubble]] しません。 --- [83] [[キャンセル可能]]とします。 --- [84] [CODE(DOMa)@en[[[message]]]], [CODE(DOMa)@en[[[filename]]]], [CODE(DOMa)@en[[[lineno]]]], [CODE(DOMa)@en[[[colno]]]] は適当に設定します。 --- [85] [CODE(DOMa)@en[[[error]]]] は [[null]] とします。 -= [86] >>79 で[[キャンセル]]されなければ、 [CODE(DOMi)@en[[[Worker]]]] の[[大域スコープ]]において [[catch]] されていない実行時エラーが発生したこととします。 -- [87] [[ワーカー]]から [CODE(DOMi)@en[[[Worker]]]] への接続が解かれている場合 (親[[ワーカー]]が終端されている場合) には、 [CODE(DOMa)@en[[[event]]]] [[イベントハンドラー]]はなく、 [CODE(DOMa)@en[[[onerror]]]] は [[null]] であるとみなします。 ]FIG] ;; [88] 従って[[専用ワーカー]]でのエラーは処理されなければ作成元をたどって結局最初の[[閲覧文脈]]に到達し、 そこから[[利用者]]へと通知されることになります。経路途中の[[ワーカー]]が破棄されている場合は >>87 によりスキップされます。 ;; [89] >>84 は適当な値がどのようなものか明確になっていませんが、元の [CODE(DOMi)@en[[[ErrorEvent]]]] と同じ値でいいのでしょうか。 (たとえ[[起源]]が違っていたとしても、 [CODE(DOMm)@en[[[postMessage]]]] によって通信できる[[ワーカー]]からの情報なので、[[起源]]を超えた情報の漏洩には当たらないはずです。 * エラーの報告 [12] [[スクリプト]]について[DFN[[RUBYB[[[エラーを報告]]]@en[report the error]]]]するとは、 次の手順をいいます [SRC[>>13]]。 [FIG[ = [14] エラーの[[対象]]が[[誤り報告モード]]なら、エラーは[[取り扱われなかった]]とし、終わります。 = [15] エラーの[[対象]]を[[誤り報告モード]]とします。 = [20] [CODE(DOMi)@en[[[ErrorEvent]]]] を用意します。 -- [26] [[trusted]] とします。 -- [27] [[bubble]] しないとします。 -- [28] [[キャンセル可能]]とします。 -- [29] [[イベント名]]は [CODE(DOMe)@en[[[error]]]] とします。 -- [21] [[スクリプト]]の[[エラーミュートフラグ]]があれば、 --- [31] [CODE(DOMa)@en[[[filename]]]] は[[空文字列]]とします。 --- [23] [CODE(DOMa)@en[[[lineno]]]] は [CODE[[[0]]]] とします。 --- [24] [CODE(DOMa)@en[[[colno]]]] は [CODE[[[0]]]] とします。 --- [22] [CODE(DOMa)@en[[[message]]]] は [DFN[[CODE[[[Script error.]]]]]] とします。 --- [25] [CODE(DOMa)@en[[[error]]]] は [[null]] とします。 -- [30] そうでなければ、 --- [32] [CODE(DOMa)@en[[[filename]]]] は[[スクリプト]]を得た元の[[資源]]の[[絶対URL]]とします。 --- [34] [CODE(DOMa)@en[[[lineno]]]] はエラーの位置として指定された[[行番号]]とします。 --- [33] [CODE(DOMa)@en[[[colno]]]] はエラーの位置として指定された[[列番号]]とします。 --- [36] [CODE(DOMa)@en[[[message]]]] はエラーを説明する[[利用者エージェント]]定義の文字列とします。 --- [35] [CODE(DOMa)@en[[[error]]]] はエラーを表す[[オブジェクト]]を用意します。 ---- [17] [[catch]] されていない[[例外]]の場合は、投げられた[[オブジェクト]]です。 ---- [18] [[JavaScript]] エラーの場合は、 [CODE(JS)@en[[[Error]]]] [[オブジェクト]]です。 ---- [19] 該当するものがなければ、 [[null]] とします。 = [37] >>20 の[[イベント]]を[[対象]]において [[dispatch]] します。 = [38] [[対象]]における[[誤り報告モード]]を終えます。 = [39] >>20 の[[イベント]]が[[キャンセル]]されていれば、エラーは[[取り扱われた]]とします。 そうでなければ、エラーは[[取り扱われなかった]]とします。 ;; [40] 本手順を終えると[[エラー]]は[DFN[[RUBYB[[[取り扱われた]]]@en[handled]]]]か[DFN[[RUBYB[[[取り扱われなかった]]]@en[not handled]]]]かのいずれかとなります。 ]FIG] [42] この[[エラーの報告]]で[[対象]]となる[[オブジェクト]]は、[[大域オブジェクト]]です。 言い換えると[[大域オブジェクト]]は[[エラー]]を報告する[[イベント]]の[[対象]]オブジェクトとなります。 [[エラー]]を報告する[[イベント]]により[[スクリプト]]が起動されることがあるので、 [[対象]]は[DFN[[RUBYB[[[エラー報告モード]]]@en[in error reporting mode]]]]フラグを持っています。 [[エラーの報告]]は[[エラー報告モード]]内では行われません。 ;; [43] つまり [CODE(DOMa)@en[[[onerror]]]] 中の[[エラー]]によって [CODE(DOMa)@en[[[onerror]]]] が再帰的に呼ばれることはなく、 ([[利用者エージェント]]が[[利用者]]に[[エラー]]を報告するなら) 必ず[[利用者]]に報告されることになります。 * エラーの位置 [44] [CODE(DOMi)@en[[[ErrorEvent]]]] には [CODE(DOMa)@en[[[filename]]]]、[CODE(DOMa)@en[[[lineno]]]]、 [CODE(DOMa)@en[[[colno]]]] という[[属性]]があり、エラーが発生した元の位置の [[URL]]、 [[行番号]]、[[列番号]]を表しています。 [45] [[HTML Standard]] は動的に作られた ([CODE(JS)@en[[[document.write]]]] などによる) [[スクリプト]]であっても、また複数行にわたる[[イベントハンドラー]]などであっても、 [[利用者エージェント]]ががんばって位置を特定することをすすめています [SRC[>>13]]。 しかしその具体的な方法は規定されておらず、[[実装の品質]]の問題であると考えられます。 * エラーの起源 [46] 異なる[[起源]]の[[資源]]を[[スクリプト]]として ([CODE(HTMLe)@en[[[script]]]] [CODE(HTMLa)@en[[[src]]]] などにより) 実行させることができますが、本来[[スクリプト]]ではない[[資源]]を実行させ、 エラーメッセージなどからその[[資源]]の内容の一部または全部を取得したり、 推測したりすることができてしまうと異なる[[起源]]の情報の流出源となってしまうため、 [[同一起源方針]]によってエラーの報告は制限されています。 [47] [[スクリプト]]の[DFN[[RUBYB[[[エラーミュート]]]@en[muted errors]]]]フラグ [SRC[>>48]] が設定されていると、 [CODE(DOMi)@en[[[ErrorEvent]]]] によって[[エラー]]が発生した事実は伝えられますが、その内容や位置にはアクセスできなくなります (>>21)。 [50] [[エラーミュートフラグ]]は、[[スクリプトの作成]]手順を呼び出す際に指定されていれば設定されます [SRC[>>49]]。 これは次の場合に設定されます。 [FIG[ - [52] [[HTML]] [CODE(HTMLe)@en[[[script]]]] [[要素]]の [[execute a script block]] 手順によって[[スクリプトが作成]]される場合で、 [[スクリプト]]が [[fetch]] により得られた場合で、 [[CORS-cross-origin]] である場合 [SRC[>>51]] - [53] [CODE(DOMm)@en[[[importScripts]]]] によって[[スクリプトが作成]]される場合で、 [[スクリプト]]が[[現職設定群オブジェクト]]と[[同一起源]]でない[[起源]]を持つ [[URL]] の[[資源]]から来た場合 [SRC[>>55]] ;; [56] 仕様書が存在しませんが、 [[SVG]] [CODE(XMLe)@en[[[script]]]] [[要素]]でも同様と思われます。 ]FIG] ;; [54] つまり [CODE(HTMLe)@en[[[script]]]] [[要素]]では [[CORS]] によって[[同一起源ポリシー]]を緩和できます。 * [CODE(DOMi)@en[ErrorEvent]] インターフェイス (DOM) [65] [DFN[[CODE(DOMi)@en[[[ErrorEvent]]]]]] [[インターフェイス]]は [CODE(DOMi)@en[[[Event]]]] [[インターフェイス]]を[[継承]]した[[インターフェイス]]です。 [SRC[>>64]] [66] 他の [CODE(DOMi)@en[[[Event]]]] と同様に、 [CODE(DOMi)@en[[[ErrorEvent]]]] [[構築子]]を使って[[実現値]]を得ることができます。[[引数]]としては[[イベント型]]と、 省略可能で[[辞書]] ([CODE(DOMi)@en[[[EventInit]]]] を継承した [DFN[[CODE(DOMi)@en[[[ErrorEventInit]]]]]]) によって各種オプションを指定できます。 [SRC[>>64]] [67] [CODE(DOMi)@en[[[ErrorEvent]]]] は[[文書環境]]と[[ワーカー環境]]の両方に[[晒されています]] [SRC[>>64]]。 ** メンバー [68] [CODE(DOMi)@en[[[ErrorEvent]]]] は [CODE(DOMi)@en[[[Event]]]] のメンバーに加えて次のメンバーを持ちます。 いずれも初期値は[[空文字列]]、[[0]]、[[null]] のいずれか適切なものです [SRC[>>64]]。 [FIG[ - [72] [DFN[[CODE(DOMa)@en[[[colno]]]]]] ([CODE(DOMi)@en[[[unsigned long]]]]) - [73] [DFN[[CODE(DOMa)@en[[[error]]]]]] ([CODE(DOMi)@en[[[any]]]]) - [70] [DFN[[CODE(DOMa)@en[[[filename]]]]]] ([CODE(DOMi)@en[[[DOMString]]]]) - [71] [DFN[[CODE(DOMa)@en[[[lineno]]]]]] ([CODE(DOMi)@en[[[unsigned long]]]]) - [69] [DFN[[CODE(DOMa)@en[[[message]]]]]] ([CODE(DOMi)@en[[[DOMString]]]]) ]FIG] [74] [[利用者エージェント]]によって[[発送]]される[[イベント]]に関しては、これらの値は >>20, >>79 のようにして決定されます。 * [CODE(DOMa)@en[onerror]] 属性 (DOM) [99] [CODE(DOMi)@en[[[GlobalEventHandlers]]]] [[インターフェイス]] [SRC[>>91]] と [CODE(DOMi)@en[[[WorkerGlobalScope]]]] [[インターフェイス]] [SRC[>>90]] の [DFN[[CODE(DOMa)@en[[[onerror]]]]]] は、 [CODE(DOMe)@en[[[error]]]] [[イベント]]に対応する[[イベントハンドラーIDL属性]]です。 [[IDL属性]]の型は [CODE(DOMi)@en[[[OnErrorEventHandler]]]] です。 ;; [100] [CODE(DOMi)@en[[[GlobalEventHandlers]]]] [[インターフェイス]]は [CODE(DOMi)@en[[[Window]]]], [CODE(DOMi)@en[[[Document]]]], [CODE(DOMi)@en[[[HTMLElement]]]] が[[実装]]しています。 [98] [DFN[[CODE(DOMi)@en[[[OnErrorEventHandler]]]]]] [SRC[>>92]] は、 [CODE(DOMi)@en[[[EventHandler]]]] とほぼ同じ[[コールバック]]型ですが、[[引数]]として通常の[[イベントハンドラー]]のような [CODE(DOMi)@en[[[Event]]]] 1つに加えて、 >>94 の場合も扱えるようになっています。 [101] [[HTML要素]]の [DFN[[CODE(HTMLa)@en[[[onerror]]]]]] [[属性]]は、 [CODE(DOMe)@en[[[error]]]] [[イベント]]に対応する[[イベントハンドラー内容属性]]です [SRC[>>91]]。 ;; [102] [CODE(HTMLe)@en[[[body]]]] [[要素]]と [CODE(HTMLe)@en[[[frameset]]]] [[要素]]では、 これらの[[イベントハンドラーIDL属性]]と[[イベントハンドラー内容属性]]は[[要素]]自身ではなく [CODE(DOMi)@en[[[Window]]]] [[オブジェクト]]に対してのものとなります。 [103] [CODE(DOMe)@en[[[error]]]] [[イベント]]は[[エラーを報告]]するためのものと、 [[HTML要素]]などで用いられる通常の[[DOMイベント]]としてのものの2種類があります。 [CODE@en[[[onerror]]]] はそのどちらにも対応する[[イベントハンドラー]]であり、 >>98 の通り両方の形に対応していますし、次に示すように挙動も変わります。 [94] [[イベントハンドラー処理アルゴリズム]]は[[イベント]]が [CODE(DOMi)@en[[[ErrorEvent]]]] で[[イベントハンドラーIDL属性]]が [CODE(DOMi)@en[[[OnErrorEventHandler]]]] として定義されている場合に、 [[コールバック]]の呼び出し時の[[引数]]を次のようにします。 [SRC[>>93]] [FIG[ = [CODE(DOMa)@en[[[message]]]] [[属性値]] = [CODE(DOMa)@en[[[filename]]]] [[属性値]] = [CODE(DOMa)@en[[[lineno]]]] [[属性値]] = [CODE(DOMa)@en[[[colno]]]] [[属性値]] = [CODE(DOMa)@en[[[error]]]] [[属性値]] ]FIG] ;; [95] 他の場合には[[引数]]としては [CODE(DOMi)@en[[[Event]]]] だけが渡されますが、 この場合は [CODE(DOMi)@en[[[Event]]]] にはアクセスできません。 [96] [[イベントハンドラー処理アルゴリズム]]は[[イベント]]が [CODE(DOMi)@en[[[ErrorEvent]]]] で[[イベント型]]が [CODE(DOMa)@en[[[error]]]] の時に、[[コールバック]]が返した値が [[WebIDL]] [[boolean]] の[[真]]の値なら、[[イベント]]を[[キャンセル]]します。 [SRC[>>93]] ;; [97] 他の場合には逆に[[偽]]の値の時、[[キャンセル]]します。 [104] [[get the current value of the event handler]] は [CODE(HTMLe)@en[[[body]]]] [[要素]]や [CODE(HTMLa)@en[[[frameset]]]] [[要素]]の [CODE(HTMLa)@en[[[onerror]]]] [[内容属性]]の値を解釈するにあたり、 [CODE(DOMp)@en[[[event]]]], [CODE(DOMp)@en[[[source]]]], [CODE(DOMp)@en[[[lineno]]]], [CODE(DOMp)@en[[[colno]]]], [CODE(DOMp)@en[[[error]]]] の5つの[[引数]]が順に与えられてるものとします。 [SRC[>>106]] ;; [105] 他の場合には [CODE(DOMp)@en[[[event]]]] のみとなります。 * 歴史 [11] [CITE[ryuzi_kambe の?D - onError="this.src=altimage";]] ([TIME[2007-06-08 01:22:17 +09:00]] 版) [1] [CITE@ja[第五章 クライアントサイドの技術:エラー処理 (try...catch)]] ([TIME[2008-12-01 09:28:12 +09:00]] 版) > このスクリプトが期待通り動作するのはInternet ExplorerとFirefoxのみです。Safari 2やOperaではwindow.onerrorの処理は無視されエラーが発生してしまいます。また、エラーメッセージやエラー行数に関しても Internet ExplorerとFirefoxでは内容が異なります(行数もカウント位置が違うため互換性がない)。 [2] [CITE[JavaScript掲示板]] ([TIME[2008-12-01 09:29:06 +09:00]] 版) >> ただし、Opera(私のは最新より1つバージョン古い)はwindow.onerrorをハンドリングできませんでした。 > ボクが使っているOperaは8.5ですが、ハンドリングできました(^_^;A >> 私の環境では、onerrorからcallerをたどれるのはIEだけでした。 >> スタックトレースの取得は(以前かぱさんがしていたように)Exceptionコンストラクタの中でして、onerrorはそれがなかったとき補助的にした方がNetscape等もサポートできるはずです。 > う~ん。私の環境(Mozilla1.7.12、Firefox1.5、Opera8.5、IE6.0、NN7.1)ではすべて取得できましたよ。 ただしOperaに関してだけは、エラーメッセージ中にスタックトレース情報が含まれていました。 また、NN(Mozilla系?)では、onerrorハンドラの第4引数に謎のスタックトレース情報が入ってきました! (今はそれを使わずに自分でcallerを使って取り直していますが…) [3] うちの [[Opera]] 9.61 でも window.onerror は効かないみたいですが。 - [5] [CITE[''''''[''''''whatwg'''''']'''''' Spec for handling runtime script errors doesn't seem to match reality]] ( ([TIME[2013-01-08 04:45:11 +09:00]] 版)) [6] [CITE[機密情報を含むJSONには X-Content-Type-Options: nosniff をつけるべき - 葉っぱ日記]] ( ([TIME[2013-05-17 04:25:50 +09:00]] 版)) ** エラーイベントの拡張 [111] [[JavaScript 1.1]] 以来、なぜか [[URL]] と[[行番号]]しかありませんでしたが、 2012年に[[列番号]]が追加されました。 [REFS[ - [4] [CITE@en[Web Applications 1.0 r6957 Try adding a fourth argument, 'column', to onerror handlers.Fixing https://www.w3.org/Bugs/Public/show_bug.cgi?id=13319]] ( ([TIME[2012-02-01 08:36:00 +09:00]] 版)) - [7] [CITE@en[Web Applications 1.0 r8087 Rename 'ErrorEvent.column' to 'colno' to match IE.]] ( ([TIME[2013-07-26 08:42:00 +09:00]] 版)) ]REFS] [112] 2013年には、[[エラー]]のオブジェクト自体にも[[エラーイベント]]からアクセスできるように拡張されました。 [REFS[ - [8] [CITE@en[Web Applications 1.0 r8086 New argument to onerror: the Error object itself.]] ( ([TIME[2013-07-25 03:50:00 +09:00]] 版)) ]REFS] ** DOM イベントとの統合 [113] 2013年には[[エラーの報告]]も特別な仕組みとしてではなく、[[DOMイベント]]の特別な場合として[[発送]]される形に変更されました。 [REFS[ - [9] [CITE@en[Web Applications 1.0 r7995 Revamp how errors are reported to be a little more sane and hopefully slightly closer to more browsers (but there's not a huge amount of interop here and so this won't exactly match anything). This is a very risky change so let me know if anything broke.]] ( ([TIME[2013-06-22 03:04:00 +09:00]] 版)) ]REFS] [10] [CITE@en[Web Applications 1.0 r8239 Drop the ability to catch 'error' events from