[24] [[イベントループ]]は、特に実行できる[[タスク]]のない[DFN[アイドル状態]]となることがあります。
[CODE(DOMm)@en[requestIdleCallback]] で[[コールバック関数]]が登録されている場合、
[[アイドル期間]]が設定され、[[コールバック関数]]が実行されます。

* 仕様書

[REFS[
- [1] [CITE@en[Cooperative Scheduling of Background Tasks]] ([TIME[2016-12-21 17:01:17 +09:00]]) <https://w3c.github.io/requestidlecallback/#h-start-an-event-loop-s-idle-period>
]REFS]

* イベントループのアイドル状態

[2] [[利用者エージェント]]は、[[イベントループ]][VAR[イベントループ]]に関して、
[RUBYB[十分な時間]@en[a non-trivial amount of time]][RUBYB[アイドル]@en[idle]]であり続けそうだと思われる場合であって、
他の[[イベントループ]]その他のより優先度の高い作業に悪影響を及ぼさないと考えられる場合には、
[VAR[イベントループ]]の新しい[[アイドル期間]]を開始する[SHOULD[べきです]] [SRC[>>1]]。

[3] [[利用者エージェント]]は、[[電力消費]]の節約のために[[文書]]が[[隠れている][document.hidden]]場合に[[アイドル期間]]を開始する頻度を下げる [SRC[>>1]] など、
適当に調整できます。

[25] アイドルとはどのような状態なのかはあまり厳密には定義されていませんが、
[[イベントループ]]ですぐに実行可能な状態の[[タスク]]が[[タスクキュー]]に見当たらないことを表しているようです。

[EG[
[26] [[ネットワーク]]待ちの [[fetch]] や、時間経過待ちの [CODE[setTimeout]]
の処理があっても、すぐに実行可能な[[タスク]]ではありませんから、
アイドル状態となり得ます。
]EG]

-*-*-

[4] [VAR[イベントループ]]の[DFN[[RUBYB[アイドル期間開始アルゴリズム]@en[start an idle period algorithm]]]]は、
次のようにしなければ[MUST[なりません]] [SRC[>>1]]。

[FIG(steps)[
= [5] [VAR[最終締切]]を、[VAR[イベントループ]]の[F[最終アイドル期間締切]]に設定します。
= [7] [VAR[今]]を、[[現在時刻]]に設定します。
= [8] [VAR[最終締切]] > [VAR[今]]なら、
== [9] ここで停止します。
= [10] [VAR[締切]]を、[VAR[今]]より大きな適切な値に設定します。
[VAR[締切]]は、[[アイドル]]状態であり続けると予想される時刻としますが、
[VAR[今]] + 50 [[ms]] [[以下]]とします。
= [11] [VAR[文書群]]を、[VAR[イベントループ]]に関連付けられた[[文書]]のうち、
[[完全に活性]]なものの[[リスト]]に設定します。
= [12] [VAR[文書群]]の各[VAR[文書]]について、
== [13] [VAR[文書]]の[F[[CODE(DOMi)@en[Window]]]]の[F[アイドル要求コールバック群のリスト]]の各項目を、
そのままの順序で、
[VAR[文書]]の[F[[CODE(DOMi)@en[Window]]]]の[F[走らせられるアイドルコールバック群のリスト]]の末尾に追加します。
== [14] [VAR[文書]]の[F[[CODE(DOMi)@en[Window]]]]の[F[アイドル要求コールバック群のリスト]]を、
空にします。
= [15] [[タスクをキューに追加]]します。
[FIG(list members)[
: [VAR[処理]] :
[FIG(steps)[
= [16] 
[VAR[イベントループ]]と[VAR[締切]]について、
[[アイドルコールバック群の呼び出しアルゴリズム]]を実行します。
]FIG]
: [VAR[タスク源]] : [[アイドルタスクタスク源]]
]FIG]
= [17] [VAR[イベントループ]]の[F[最終アイドル期間締切]]を、[VAR[締切]]に設定します。
]FIG]

[6] [VAR[イベントループ]]は、
[DFN[[F[[RUBYB[[[最終アイドル期間締切]]]@en[last idle period deadline]]]]]]を持ちます。
初期値は [N[0]] です。 [SRC[>>1]]

[20] [VAR[締切]]は、[[利用者エージェント]]が任意の基準で決定できます。
[CODE(DOMm)@en[requestIdleCallback]] の[[コールバック]]の実行で、
他の時間に厳しいタスクが遅延してしまわないように注意する必要があります。
そのため、次の最小値とするべきです [SRC[>>1]]。

[FIG(list)[
- [21] [CODE(DOMm)@en[setTimeout]] と [CODE(DOMm)@en[setInterval]] の[[タイマー]]で直近のもの
- [22] [CODE(DOMm)@en[requestAnimationFrame]] の[[コールバック]]の次の実行
- [23] 次のフレームの[[レンダリング]]、音声処理、その他[[利用者エージェント]]が重要と考える内部処理の次の実行
]FIG]

[18] [DFN[[RUBYB[アイドル期間]@en[idle period]]]]とは、
[VAR[今]]から[VAR[締切]]までをいいます。
[VAR[イベントループ]]の[[アイドル期間]]は、同時に複数開始することはできません。
[SRC[>>1]]

[29] [[アイドル期間開始アルゴリズム]]は、[[イベントループ]]から呼び出されます。

[19] [[利用者エージェント]]は、途中で[[アイドル]]状態でなくなったと判断したら、
[VAR[締切]]を待たずに[[アイドル期間]]を打ち切ることもできます。
その場合であっても、[VAR[締切]]まで次の[[アイドル期間]]は開始できません。 [SRC[>>1]]

* 関連

[217] [[ワーカー]]が [[protected worker]] でなくなるとは、
このアイドル状態に近いものを指しているようです ([[ワーカー]]の性質により、
本項での説明とは異なる点もあります)。

[27] [[アイドル状態]]と [[busy indicator]] が停止している状態は一致しません。

* メモ

[130] [[ブラウザー拡張]]や[[埋め込みブラウザー]]、他の[[アプリケーション]]から
[[Webブラウザー]]を制御する [[API]] などは、 [[Webページ]]の読み込みが終わり
「安定」した状態 ([[idle]] 状態) になったことを検知したい場合があります。

[EG[
[131] 例えば [[Webページ]]の表示が完了したら[[スクリーンショット]]を撮るソフトウェアの実装には、表示の完了のタイミングを知る必要があります。ここでいう表示の完了は、
必ずしも [[completely loaded]] ではなく、読み込み完了後に遅延して実行される[[スクリプト]]の完了も待ちたいです。
]EG]

[EG[
[132] [[Webアプリケーション]]の[[テスト]]のために外部から [[Webブラウザー]]を制御する場合、
[[クリック]]などの入出力操作を擬似的に発生させ、それに対する[[スクリプト]]の一連の動作が終わったら、
その時点の状態を確認したいかもしれません。
]EG]

[133] この状態は仕様上の概念ではありませんから ([[Webサイト]]の[[相互運用性]]には影響しません)、
判断方法はそれぞれの実装によります。一般的には、次のように判断するのが妥当でしょう。
[FIG(list)[
- [134] [[stops parsing]] ([[completely loaded]]) より後であり、 [CODE(JS)@en[[[document.open]]]] されていない
- [135] どの[[タスクキュー]]にも実行可能な[[タスク]]がない
- [136] [[マイクロタスク]]その他の実行可能な処理がない
- [138] 数秒以内に実行可能なタイマー ([CODE(DOMm)@en[[[setTimeout]]]] や
[CODE(HTTP)@en[[[Refresh]]]] など) がない
- [185] 実行中の [[fetch]] がない
- [205] 実行中の[[データベース取引]]がない
- [194] または、他の条件が満たされずとも、[[モーダルダイアログ]]の表示中である
]FIG]

[177] [[媒体]]の[[再生]]、[[アニメーション]]、[[ワーカー]]の実行、
[CODE(DOMi)@en[[[EventSource]]]] や [CODE(DOMi)@en[[[WebSocket]]]] などは、
無視するのが適当そうです。

[193] 無限に読み込みが続く場合や[[スクリプト]]により[[アニメーション]]する場合など、
この定義の「アイドル状態」に至らないこともあり得ます。


[28] [CITE@en[Integrate with requestIdleCallback]]
([[rmcilroy]]著, [TIME[2018-10-25 23:57:45 +09:00]])
<https://github.com/whatwg/html/commit/01787ee712a7803e64e0da6ac9644a5e6b8d2cca>

[30] [CITE@en[Missing definition for "idle time" · Issue #70 · w3c/requestidlecallback]]
([TIME[2018-11-06 23:02:39 +09:00]])
<https://github.com/w3c/requestidlecallback/issues/70>

[31] [CITE@en[Hook into HTML spec. by rmcilroy · Pull Request #75 · w3c/requestidlecallback]]
([TIME[2018-11-06 23:05:55 +09:00]])
<https://github.com/w3c/requestidlecallback/pull/75>

[32] [CITE@en[Integrate with requestIdleCallback by domenic · Pull Request #3570 · whatwg/html]]
([TIME[2018-11-06 23:06:24 +09:00]])
<https://github.com/whatwg/html/pull/3570>

[33] [CITE@en[Integrate with requestIdleCallback by rmcilroy · Pull Request #4104 · whatwg/html]]
([TIME[2018-11-06 23:09:07 +09:00]])
<https://github.com/whatwg/html/pull/4104>