[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]] 版) ]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ブラウザー]]があるのか知りませんが...)]] ** スピン [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]] 待ち) * 歴史 [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] [[イベント・ループ]]は、 [[storage mutex]] を所有することができます。 * メモ [1] [CITE@en[Timing and Synchronization in JavaScript - Opera Developer Community]] ([TIME[2009-06-07 11:12:38 +09:00]] 版)