requestIdleCallback()Copyright © 2025 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
本書は、ウェブページの作成者が、同じイベントループを共有する他の高優先度タスク(入力処理、アニメーション、フレーム合成など)に遅延を発生させることなく、協調的にバックグラウンドタスクをスケジューリングできるAPIを定義します。ユーザーエージェントは、現在スケジュールされているタスク、vsyncの締め切り、ユーザーインタラクションなどの知識をもとに、ユーザーに知覚される遅延やアニメーションのカクつき、入力応答の悪化を発生させずにバックグラウンドタスクを実行するタイミングを、より適切に判断できます。そのため、このAPIを使用することで、ブラウザがアイドル状態となる時間帯にバックグラウンドタスクのより適切なスケジューリングが実現されます。
このセクションでは、本書の発行時点でのステータスについて説明します。現在のW3C発行物と本技術レポートの最新版は、 W3C標準とドラフト一覧(https://www.w3.org/TR/)でご覧いただけます。
Web Performance Working Group は仕様用のテストスイートを管理しています。ワーキンググループの実装レポートもご参照ください。本ドキュメントの実装に関心のあるベンダーは、下記のメーリングリストに参加し、議論に加わることを推奨します。
この文書はWeb Performance Working Groupにより、勧告トラックを使用してワーキングドラフトとして公開されました。
ワーキングドラフトとしての公開は、W3Cおよびその会員による承認を意味しません。
この文書はドラフトであり、今後いつでも他の文書によって更新・差し替え・廃止される可能性があります。進行中の作業以外の文書として引用するのは適切ではありません。
このドキュメントは、W3C特許ポリシーのもとで活動するグループにより作成されました。 W3C は、グループの成果物に関連してなされた特許開示の公開リストを管理しています。そのページには特許開示の手順も掲載されています。特許について実際に知っている人は、Essential Claim(s)を含むと考えた場合、W3C特許ポリシーの第6節に従って情報を開示する必要があります。
この文書は 2023年11月3日付けW3Cプロセス文書に従って管理されています。
このセクションは規範的ではありません。
ウェブページは、時間的に重要ではないものの、実行にかなりの時間がかかる可能性がある計算タスクを、ブラウザのイベントループで実行したい場合がよくあります。そのようなバックグラウンドタスクの例として、アナリティクスデータの記録、長時間かかるデータ処理操��、クライアントサイドのテンプレート処理や、近い将来表示される可能性が高いコンテンツのプリレンダリングなどが挙げられます。これらのタスクは、入力への反応やrequestAnimationFrame()
を使ったスクリプトベースのアニメーションなど、他の時間的に重要な処理とイベントループを共有しなければなりません。これらのバックグラウンドタスクは、通常、setTimeout()
でコールバックをスケジューリングし、そのコールバック内でバックグラウンドタスクを実行することで行われます。
この方法の欠点は、スクリプトの作成者が、あるsetTimeout()
コールバックが時間的に重要なのか、それともブラウザがアイドル状態になるまで遅延してもよいものなのかをユーザーエージェントに伝える方法がないことです。さらに、ユーザーエージェントは、コールバックが時間的に重要な処理を遅延させたり、カクつきなどのユーザが気づく遅延を引き起こさずに、どの程度の時間まで実行し続けられるかの情報をコールバックに提供できません。その結果、もっとも簡単な対応策は、setTimeout()
を非常に小さな値で呼び出し、そこで最小限の作業を実行し、さらに必要な作業をsetTimeout()
でもう一度スケジューリングすることです。しかしこの方法は、ユーザーエージェントのイベントループに複数の小さいタスクを投稿してその実行をスケジューリングする余分なオーバーヘッドが発生します。また、各コールバックの合間にユーザーエージェントが他の時間的に重要な処理を適切に割り込ませる必要があるため、各コールバックの実行にかかる時間をユーザーエージェントが正確に推測できない点も問題です。
本書で解説するAPIは、スクリプト作成者が、ユーザーエージェントがアイドル状態であるときにコールバックのスケジューリングをリクエストできるようにします。ユーザーエージェントは、どれくらいアイドル状態が続くと見積もっているかを、コールバックに渡される期限(deadline)として提供します。ページ作成者はこの期限を使って、これらのバックグラウンドタスクがアニメーションや入力応答などの遅延が許されないイベントに影響を与えないようにできます。
以下はこのAPIを使ってバックグラウンドタスクを書く例です。
<!DOCTYPE html>
<title>requestIdleCallbackを使用したバックグラウンドタスクのスケジューリング</title>
<script>
var requestId = 0;
var pointsTotal = 0;
var pointsInside = 0;
function piStep() {
var r = 10;
var x = Math.random() `*` r `*` 2 - r;
var y = Math.random() `*` r `*` 2 - r;
return (Math.pow(x, 2) + Math.pow(y, 2) < Math.pow(r, 2))
}
function refinePi(deadline) {
while (deadline.timeRemaining() > 0) {
if (piStep())
pointsInside++;
pointsTotal++;
}
currentEstimate = (4 `*` pointsInside / pointsTotal);
textElement = document.getElementById("piEstimate");
textElement.innerHTML="円周率推定値: " + currentEstimate;
requestId = window.requestIdleCallback(refinePi);
}
function start() {
requestId = window.requestIdleCallback(refinePi);
}
function stop() {
if (requestId)
window.cancelIdleCallback(requestId);
requestId = 0;
}
</script>
<button onclick="start()">クリックで開始</button>
<button onclick="stop()">クリックで停止</button>
<div id="piEstimate">未開始</div>
このセクションは規範的ではありません。
入力処理、描画や合成など、そのフレームの処理が完了したあと、ユーザーエージェントのメインスレッドは次のいずれかのタイミングまでしばしばアイドル状態になります:次のフレーム処理の開始、未処理のタスクが実行可能になる、またはユーザー入力がある場合です。本仕様は、こうしたアイドル時間にrequestIdleCallback() APIを
使ってコールバックの実行をスケジューリングする方法を提供します。
requestIdleCallback() API
経由で投稿されたコールバックは、ユーザーエージェントが定義したアイドル期間中に実行対象となります。アイドルコールバックが実行されると、その時のアイドル期間の終了時点に対応する期限(deadline)が渡されます。アイドル期間がいつかはユーザーエージェントごとに定義されますが、一般的にはブラウザがアイドル状態になる静穏時に発生することが期待されます。
アイドル期間の一例は、アクティブなアニメーション中に特定のフレームを画面にコミットした後、次のフレームの処理を開始するまでの間で、図 1で示されています。こうしたアイドル期間は、アクティブなアニメーションや 画面更新中に頻繁に発生しますが、通常ごく短時間(たとえば60Hzのvsyncサイクルのデバイスでは16ms未満)です。
ウェブ開発者は、アイドルコールバック中に実行するすべての作業を考慮しておくべきです。Promiseの解決やページレイアウトの発生など、一部の操作は、アイドルコールバック終了後に後続のタスクをスケジューリングする場合があります。このような場合、次のフレーム締め切り前にこれらの操作が実行できるよう、期限満了前に(コールバック側が)処理を明け渡すことで追加作業に対応させるべきです。
アイドル期間の別の例として、ユーザーエージェントがアイドルで、画面更新が発生していないときがあります。このような場合、ユーザーエージェントはアイドル期間の終了を制約できる後続タスクを持たないことがあります。予測不能なタスク(たとえばユーザー入力処理など)による、ユーザが気づく遅延を回避するため、こうしたアイドル期間の長さは最大値50msに制限すべきです。アイドル期間が終了してもユーザーエージェントが引き続きアイドルであれば、図 2のように、追加のアイドル期間をスケジューリングし、長いアイドル時間帯でもバックグラウンド処理が続けて行えるようになります。
アイドル期間中、ユーザーエージェントはFIFO順でアイドルコールバックを実行し、アイドル期間終了または実行待ちのコールバックがなくなるまで繰り返します。そのため、すべてのアイドルコールバックが一つのアイドル期間中に必ずしも実行されるとは限りません。残ったアイドルタスクは次のアイドル期間で実行対象になります。
性能を最大限に発揮するため、開発者は意味のないコールバック(例えばrequestAnimationFrameやsetTimeout等)を不要に残さず、イベント対応が必要になった時点でのみスケジューリングしてください。このパターンは全体の効率を高め、ユーザーエージェントがバックグラウンド作業に効率的に使える長いアイドルコールバック(最大50ms)のスケジューリングを実現します。
現在のアイドル期間の開始前に投稿されたタスクだけがその期間中に実行対象となります。そのため、アイドルコールバック中にrequestIdleCallback()
でもうひとつコールバックを投稿した場合、その後続コールバックは今のアイドル期間中には実行されません。これにより、アイドルコールバックが期限までに処理を終えられない場合、将来のアイドル期間に自身を再投稿するコードパターン(下記例のような)が可能になります――このとき短すぎるアイドル期間中にコールバックが何度も実行されてしまうことはありません:
function doWork(deadline) {
if (deadline.timeRemaining() <= 5) {
// これには5ms以上かかるので、
// 十分長い締め切りで次回呼ばれるのを待つ。
requestIdleCallback(doWork);
return;
}
// 処理を行う...
}
次のアイドル期間の開始時、新たに投稿されたアイドルコールバックは実行可能なタスクリストの末尾に追加されます。これにより、コールバックの再投稿はラウンドロビン方式で実行されることが保証され、すべてのコールバックが先行するタスクの再投稿コールバックよりも先に一度は実行されることになります。
本仕様の将来バージョンでは他のスケジューリング戦略も認められる可能性があります。たとえば「同じアイドル期間中にスケジュール」「アイドル時間がXミリ秒以上の期間中」等。現行仕様では次のアイドル期間へのスケジューリングだけをサポートしており、その際にコールバックがロジックを実行するか、さらに再投稿で次のアイドル期間への移行ができます。
ユーザーエージェントがウェブページをユーザ不可視と判断した場合、デバイスの電力消費を減らすためにアイドル期間を間引くことがあります。例として、連続ではなく10秒ごとに一回だけアイドル期間を呼び出すなどです。
最後に注意すべき点として、ページの負荷が高い場合、ユーザーエージェントがアイドルCPU時間を全く確保できない場合もあります。そのため、requestIdleCallback()
API経由で投稿されたアイドルコールバックは、無期限に実行が延期される可能性があり、その場合アイドル期間自体がスケジューリングされないこともあります。コールバックをアイドル期間中に実行したいものの、実行期限を設けておきたい場合には、options引数のtimeoutプロパティを指定できます。指定したタイムアウトが先に到達した場合は、アイドル期間外でもタスクがキューイングされて実行されます。
最大50msという期限値は、研究 [RESPONSETIME]に基づいています。これによれば、ユーザー入力に100ms以内に応答すると、人間にはほぼ瞬時に反応したと認識されます。アイドル期限を50msに制限することで、仮にアイドルタスクが開始直後にユーザー入力があった場合でも、ユーザーエージェントはその入力に50ms以内で反応できるため、遅延が知覚されません。
「規範的ではありません」と記されたセクションだけでなく、本仕様中のすべての著述ガイドライン、図、例、注記も規範的ではありません。この仕様のその他全ては規範的です。
このドキュメント中のキーワードMUST、REQUIRED、SHALL、SHOULD は、 BCP 14 [RFC2119] [RFC8174] に記載されている通りに解釈してください。ただし、例示のようにすべて大文字で出てきた場合(のみ)。
本仕様中のIDL断片は、準拠IDL断片に必要な形式としてMUST解釈されます。
この仕様で定義される適合クラスは一つだけです:
Windowインターフェース拡張参照)でもなければなりません。
Window
インターフェース拡張以下のIDL断片の partial interface は、
requestIdleCallback()
操作を
Window
オブジェクト上に公開するために使用されます。
WebIDLpartial interface Window {
unsigned long requestIdleCallback(IdleRequestCallback callback, optional IdleRequestOptions options = {});
undefined cancelIdleCallback(unsigned long handle);
};
dictionary IdleRequestOptions {
unsigned long timeout;
};
[Exposed=Window] interface IdleDeadline {
DOMHighResTimeStamp timeRemaining();
readonly attribute boolean didTimeout;
};
callback IdleRequestCallback = undefined (IdleDeadline deadline);
各 Window
は以下を持つ:
Window
オブジェクトの存続期間内で一意の番号が割り当てられていなければならない。Window
オブジェクトの存続期間内で一意の番号が割り当てられていなければならない。requestIdleCallback(callback, options)
が
IdleRequestCallback
および省略可能な IdleRequestOptions で呼び出されたとき、ユーザーエージェントは
次の手順を実行しなければならない:
Window
オブジェクトとする。以下の手順は並列に実行され、省略可能な timeout プロパティが指定された場合
setTimeout() に似たタイマーがキューされる。ここから、アイドルとタイムアウト両者のコールバックはレース状態となり、
一方が先にスケジュールされれば他方をキャンセルする(例: アイドルコールバックが先にスケジュールされた場合はタイムアウトコールバックがキャンセルされ、その逆も同様)。
timeout
プロパティが options に存在し値が正の場合:
これは省電力のため、ユーザーエージェントが必要に応じてタイムアウトをパディングできるよう意図されたもの。 たとえば一部のプロセッサは低消費電力モード時にタイマーの粒度が粗くなるため、こうしたプラットフォームでは 高精度タイマーによる消費増大を避けるため、ユーザーエージェントはタイマーを遅延させてもよい。
requestIdleCallback()
は単一のコールバックだけをスケジューリングし、単一の
アイドル期間中に実行される。コールバックが指定期限までに処理を終えられない場合は、
(コールバック内部で)再度
requestIdleCallback()
を呼び出して続きを将来のコールバックとしてスケジューリングし、すぐに処理を抜けて
イベントループ
に制御を返すべきである。
cancelIdleCallback()
メソッドは、以前スケジューリングをリクエストしたアイドルコールバックをキャンセルするためのものである。
cancelIdleCallback(handle)
が呼ばれたとき、ユーザーエージェントは次の手順を実行しなければならない:
Window
オブジェクトとする。cancelIdleCallback()
は、window の アイドルリクエストコールバックのリスト
または 実行可��なアイドルコールバックのリスト
のエントリに対して呼ばれることがある。いずれの場合もそのエントリはリストから削除され、コールバックは実行されない。
各 IdleDeadline には 期限時刻の取得アルゴリズム が関連付けられており、
これは期限となる絶対時刻(ミリ秒単位)の
DOMHighResTimeStamp
を返す。
初期値はゼロになる。
timeRemaining() メソッドが
IdleDeadline オブジェクトで呼ばれた場合、
期限切れまでの残り時間を
DOMHighResTimeStamp
で返さなければならない。この値は計測可能だがタイミング攻撃を防止できる程度にせよ ― 詳細は [HR-TIME] の「Privacy and
Security」を参照。この値は以下の手順で計算:
DOMHighResTimeStamp
型で現在の高解像度時刻(ミリ秒)として取得する。
IdleDeadline の 期限時刻の取得アルゴリズム の結果とする。各 IdleDeadline には timeout が関連付けられ、初期値は false である。
didTimeout
ゲッターは必ず
timeout
を返す。
アイドルコールバックタイムアウトアルゴリズム は
timeout を true にし、これは登録時に渡された
IdleRequestOptions のタイムアウトプロパティ値超過により
アイドル期間外でコールバックが実行されることを示す。
アイドル期間を開始するには、Window
window と
getDeadline(DOMHighResTimeStamp
を返すアルゴリズム)を与えて行う:[HR-TIME]
このアルゴリズムは イベントループ処理モデル により、イベントループが アイドルであると判断したときに呼び出される。
これはユーザーエージェントが必要に応じてデバイスの省電力最適化のため、アイドル期間の開始を遅らせられるようにする意図です。たとえば、Document の visibility
state が "hidden" の場合は、ユーザーエージェントはアイドル期間生成を間引き、
たとえば10秒に1度だけアイドル期間を発生させて省電力最適化を行うことができる。
現在から期限(deadline)までの時間をアイドル期間という。同じWindow
につきアクティブなアイドル期間は同時に1つしか存在しない。ユーザーエージェントはアイドルでなくなったと判断した時点で
このアイドル期間を早期終了でき、その場合次のアイドル期間はdeadlineより後にしか始まらない。
アイドルコールバック呼び出しアルゴリズムをWindow
window と
getDeadline(DOMHighResTimeStamp
を返すアルゴリズム)で行う:[HR-TIME]。
IdleDeadline
を生成し、その期限時刻の取得アルゴリズムをgetDeadline
にする。このdeadlineArgを用意する。
report"を引数に呼び出す。
ユーザーエージェントは、たとえdeadlineに達していなくても、ステップ1のリターンでアイドル期間を早期終了してよい。 たとえば高優先度作業が実行可能になった場合などで判断される。
アイドルコールバックタイムアウトアルゴリズム:
IdleDeadline
の新しいインスタンスdeadlineArgを用意し、期限時刻取得にはnowを返すアルゴリズムを設定し、
timeoutもtrueに設定する。
report"を引数に呼び出す。
アイドルコールバックをスケジューリングすると、ユーザーエージェントはどのくらいアイドル状態で居��けるつもりかの推定値を提供する。この情報は、そのフレーム内で他のアプリタスクやブラウザー処理にかかる時間を推定するのに利用できる。ただし、開発者はすでに他の手段(たとえばrequestAnimationFrameでフレームの開始をマークし、次のフレーム時刻を推定してあらゆるコールバック内で「残り時間」を計算するなど)で得ることは可能である。
IdleDeadlineインターフェースで返すこの時間推定値の精度は、
キャッシュや統計的フィンガープリント攻撃への対策として、coarsen time を
cross-origin
isolated capability 基準で粗くすることで、このAPIが他のタイマーAPI以上の情報を公開しないようにすべきである。
[HR-TIME]
TBD
編集者は、本仕様への貢献者として以下の方々に謝意を表します: Sami Kyostila, Alex Clarke, Boris Zbarsky, Marcos Caceres, Jonas Sicking, Robert O'Callahan, David Baron, Todd Reifsteck, Tobin Titus, Elliott Sprehn, Tetsuharu OHZEKI, Lon Ingram, Domenic Denicola, Philippe Le Hegaret and Anne van Kesteren.
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: