[3] [[Webブラウザー]]における[[イベント]]、[[fetch]]、[[構文解析]]、[[スクリプト]]実行、 [[レンダリング]]その他の動作の相互作用は、 [DFN[[RUBYB[[[イベント・ループ]]]@en[event loop]]]]によって説明されています。 [15] 非同期システム、 [[GUI]] システムの同様の概念に倣って[[イベント・ループ]]と呼ばれていますが、 実際に [[Webブラウザー]]で実行される処理の単位は[[イベント]]ではなく、[[タスク]]と呼ばれています。 [[DOM]] の[[イベント]]は[[タスク]]であることもあれば、[[タスク]]の処理の一部分であることもあります。 * 仕様書 [REFS[ - [5] '''[CITE@en-US-x-hixie[HTML Standard]] ([TIME[2012-03-28 21:58:58 +09:00]] 版) ''' - [40] '''[CITE@en-US-x-hixie[HTML Standard]] ([TIME[2012-03-28 21:58:58 +09:00]] 版) ''' - [41] '''[CITE@en-US-x-hixie[HTML Standard]] ([TIME[2012-03-28 21:58:58 +09:00]] 版) ''' - [44] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2012-03-28 21:58:58 +09:00]] 版) ]REFS] * メインのイベント・ループ [6] [[利用者エージェント]]は、[[イベント]]、[[利用者]]との対話、[[スクリプト]]、 [[レンダリング]]、[[ネットワーク]]処理、その他の協調のために[[イベント・ループ]]を使わ[['''なければなりません''']]。 [[イベント・ループ]]は[[利用者エージェント]]毎に少なくても1つ[['''なければなりません''']]。 [[関係する類似起源閲覧文脈の単位]]毎に高々1つの[[イベント・ループ]]を有することができます。 [SRC[>>5]] ;; [8] つまり、[[利用者エージェント]]全体で1つの[[イベント・ループ]]を共有することもできますし、 [[タブ]]毎などの単位で複数の[[イベント・ループ]]に分けることもできるのですが、 その分け方として、 ([CODE(JS)@en[[[document.domain]]]] を考慮した) [[起源]]ごとのグループを分離してはいけない、 ということです。 ;; [9] 仕様上明記されていませんが、おそらくここでいう「[[利用者エージェント]]」の単位は恣意的に決めることができ、 例えば通常モードと秘密モードがあり、両者で開いている [[Web頁]]同士が同じ[[起源]]であっても [[JavaScript]] でアクセスできないなら、これは2つの[[利用者エージェント]]であり、 この規定に違反せずに別々の[[イベント・ループ]]を有することができるはずです。 ;; [7] 1つの[[関連する類似起源閲覧文脈の単位]]に対して複数の[[イベント・ループ]]があると、 そこに属するいずれかの[[閲覧文脈]]が他の[[関連する類似起源閲覧文脈の単位]]に属するような [[navigate]] が発生した時に複雑なことになります。 HTML 仕様はそれをどう処理するか現在定義していません。 [SRC[>>5]] (複雑なこと、というのは具体的には示されていません。) [10] [[イベント・ループ]]は、最低1つ[[閲覧文脈]]を持ちます。 [[イベント・ループ]]のすべての[[閲覧文脈]]が捨てられる時、[[イベント・ループ]]自体も捨てられます。 逆に[[閲覧文脈]]は1つ[[イベント・ループ]]を持ちます。 [SRC[>>5]] [11] [[イベント・ループ]]は1つ以上の[[タスク・キュー]]を持ちます。 [SRC[>>5]] ** 実行 [13] [[イベント・ループ]]は、存在する限り次の手順を連続的に走らせなければ[['''なりません''']] [SRC[>>5]]。 [FIG[ = [[イベント・ループ]]のいずれかの[[タスク・キュー]]の最古の[[タスク]]を走らせます。 -- ただし、関連付けられた [CODE(DOMi)@en[[[Document]]]] が[[完全に活性]]でないものは無視します。 -- [[利用者エージェント]]は任意の[[タスク・キュー]]を選んで構いません。 = [[イベント・ループ]]が [[storage mutex]] を所有していれば、これを[[解放]]して[[自由]]にします。 = 選んだ[[タスク]]を[[タスク・キュー]]から削除します。 = [[マイクロタスク・チェックポイントを行います]]。 = [[安定状態を提供します]]。 = 必要があれば、任意の [CODE(DOMi)@en[[[Document]]]] や[[閲覧文脈]]の[[レンダリング]]や[[利用者インターフェイス]]を更新して現在の状態を反映させます。 = [[イベント・ループ]]の最初の手順に戻ります。 ]FIG] ;; [14] この辺の処理は[[利用者エージェント]]が実行される [[OS]] や実装に使っている[[ライブラリー]]等の影響を受けたり、 あるいは何を優先的に実行するかは[[実装の品質]]の問題であって [[Webブラウザー]]実装者が工夫して競合するべき点でもあることから、 仕様としてはあまり具体的に規定せず、かなり自由度を持たせているようです。 ;; [16] [[イベント・ループ]]とは別に、[[算法]]の一部分が[[非同期]]的に実行されると規定されているものがあります。 そのような[[算法]]についても、結果を何らかの形で [[DOM]] に反映させる必要があり、 [[イベント・ループ]]が[[安定状態を提供]]することによってそのような[[算法]]の[[同期区間]]が実行される、 という形で[[イベント・ループ]]と統合されています。 [[マルチスレッド]]な実装なら[[同期区間]]の前後の[[非同期]]な部分は[[イベント・ループ]]とは別の[[スレッド]]で実装してもよいでしょうし、単一[[スレッド]]なら仕様上の[[イベント・ループ]]を含むより大きな[[イベント・ループ]]の中で交互に処理を行うことになるのでしょう。 [WEAK[(単一[[スレッド]]の [[Webブラウザー]]があるのか知りませんが...)]] [48] 「[[スクリプトをブロックしているスタイル・シート]]」の定義は「最後に[[イベント・ループ]]の手順1に到達した時」 の状態を参照しています。 ** スピン [17] ある条件が成立するまで[DFN[[RUBYB[[[イベント・ループをスピン]]]@en[spin the event loop]]]]するという時、 次のようにしなければ[['''なりません''']]。 [SRC[>>5]] [FIG[ - [18] 実行中の [WEAK[([[スピン]]させた)]] [[タスク]]は実行を中断します。 [[イベント・ループ]]はそのまま [WEAK[(通常の終了と同じように)]] 次へと進めます。 - [19] 指定された条件が成立したら、 -- [20] 中断した[[タスク]]の続きを再開する[[タスクをキューに追加]]します。 [[タスク源]]は元の[[タスク]]と同じとします。 ]FIG] [25] [CODE(JS)@en[[[document.close]]]] は[[スピン]]するまで[[字句化]]を行います。 *** スピンする状況 [21] [[スピン]]する[[算法]]には次のものがあります。 - [22] [[update the session history with the new page]] ([[素片識別子]]の示す場所まで[[スクロール]]するタイミング待ち) - [23] [CODE(DOMm)@en[[[showModalDialog]]]] ([[ダイアログ]]が閉じられるの待ち) - [24] [CODE(HTMLe)@en[[[script]]]] [[要素]]の[[終了タグ]]の処理、 [[stop parsing]] (他の[[スクリプト]]の実行や[[スタイル・シート]]の準備完了や [[delay the loading]] 待ち) ** 一時停止 [26] ある条件が満たされるまで[[利用者エージェント]]を[DFN[[RUBYB[一時停止]@en[pause]]]]する場合、 次のようにしなければ[['''なりません''']]。 [SRC[>>5]] [FIG[ = [27] [[非同期]]に実行されている[[算法]]があって[[安定状態を待つ]]状態なら、 [[同期区間]]を実行してから、 (適切であれば) [[非同期]]算法の実行を再開します。 = [28] 必要があれば、任意の [CODE(DOMi)@en[[[Document]]]] や[[閲覧文脈]]の[[レンダリング]]や[[利用者インターフェイス]]を更新して現在の状態を反映させます。 = [29] 条件が満たされるまで待ちます。 =- [30] [[イベント・ループ]]はこの間他の[[タスク]]を走らせては[['''なりません''']]し、 現在走っている[[タスク]]も[[ブロック]]しなければ[['''なりません''']]。 =- [31] [[利用者]]の入力に対しては反応し続ける[['''べき''']]ですが、 [[イベント・ループ]]が何も実行しないので、低能力で動作する[['''べき''']]です。 ]FIG] *** 一時停止する状況 [32] [[一時停止]]する[[算法]]には次のものがあります。 - [33] [[prompt to unload a document]] ([CODE(DOMe)@en[[[beforeunload]]]] の[[ダイアログ]]) - [34] [[obtain the storage mutex]] ([[storage mutex]] 待ち) - [35] [CODE(JS)@en[[[alert]]]] - [36] [CODE(JS)@en[[[confirm]]]] - [37] [CODE(JS)@en[[[prompt]]]] - [38] [[printing steps]] ([[印刷]]) * ワーカーのイベント・ループ [42] [[ワーカー]] ([CODE(DOMi)@en[[[WorkerGlobalScope]]]]) は、それぞれ別個の[[イベント・ループ]]を有します。 [SRC[>>40]] [[ワーカー]]の[[イベント・ループ]]はメインの[[イベント・ループ]]と同じように処理されますが、 [[run a worker]] [[算法]]に組み込まれており、 [DFN[[[closing]]]] [[フラグ]]の存在など微妙に定義が違っています。 * 非同期的に実行される算法 [43] [[Webブラウザー]]では次の算法がそれぞれ非同期的に実行されます。 [FIG[ - イベント・ループ -- メインの[[イベント・ループ]] (>>13) -- [[run a worker]] (ワーカーのイベント・ループ >>42) - 同期区間がある算法 -- 一覧は[[同期区間]]の項を参照 --- [CODE(HTMLe)@en[[[img]]]] や [CODE(HTMLe)@en[[[audio]]]] などにおける[[資源]]の扱いに関する算法 - その他の算法 (仕様上、「asynchronously」または「in the background」と記されているもの) -- [[fetch]] (途中から) -- [CODE(JS)@en[[[document.load]]]] (途中から) -- [CODE(HTMLe)@en[[[canvas]]]] の [CODE(DOMm)@en[[[toBlob]]]] (途中から) -- [[downloading hyperlinks]] (途中から) -- [[navigate]] (途中から) -- [[application cache download process]] -- [CODE(DOMm)@en[[[setTimeout]]]]、[CODE(DOMm)@en[[[setInterval]]]] (途中から) -- [CODE(DOMi)@en[[[Worker]]]] [[構築子]] (途中から) -- [CODE(DOMi)@en[[[SharedWorker]]]] [[構築子]] (途中から) -- [CODE(DOMi)@en[[[EventSource]]]] の [[reestablish the connection]] -- [CODE(DOMm)@en[[[postMessage]]]] (途中から) -- [CODE(HTMLa)@en[[[ping]]]] の送信 -- [CODE(DOMi)@en[[[EventSource]]]] [[構築子]] (途中から) -- [CODE(DOMi)@en[[[WebSocket]]]] [[構築子]] (途中から) ]FIG] [47] 実際にはこの他に更に[[利用者インターフェイス]]など色々な要素が絡んできます。 * イベント・ループとの相互作用が不明なもの [46] [[HTML]] 以前に規定されたものや、 [[HTML]] 以後であっても明確な仕様が存在しないものは、 [[イベント・ループ]]とどう相互作用するのか文書化されていません。 [45] [[XSLT]] の処理と[[イベント・ループ]]の関係は定義されていません。 [SRC[>>44]] * 歴史 [4] [[イベント・ループ]]の概念は [[Web Applications 1.0]] ([[HTML Living Standard]]) によってはじめて体系的に説明、仕様化されました。 [REFS[ - [2] [CITE@en[Web Applications 1.0 r6966 Allow browsers to bail early for showModalDialog, alert, confirm, and prompt during pagehide, beforeunload, and unload events.]] ( ([TIME[2012-02-07 07:54:00 +09:00]] 版)) ]REFS] * 関連 [12] [[イベント・ループ]]は、[[ストレージ・ミューテックス]]を所有することができます。 ;; [39] [[ストレージ・ミューテックス]]は[[利用者エージェント]]全体で1つなので、 [[ストレージ・ミューテックス]]の解放待ちのために[[イベント・ループ]]全体がブロックされることがあります。 * メモ [1] [CITE@en[Timing and Synchronization in JavaScript - Opera Developer Community]] ([TIME[2009-06-07 11:12:38 +09:00]] 版)