requestIdleCallback は「ブラウザがヒマなときにやってもらう雑用係」
requestIdleCallback は、
「今すぐじゃなくて、ブラウザがヒマになったタイミングでやってほしい処理」を予約するための関数 です。
ユーザーの操作に直結する処理(クリックへの反応、入力の反映など)は、できるだけ即座に実行したいですよね。
一方で、
ログの送信
重くないけど地味に時間がかかる集計
次に使うかもしれないデータの事前計算
みたいな「急ぎじゃない処理」は、
ブラウザがヒマなときに回してもらったほうが、体感が軽くなります。
その「ヒマなときにやってもらう仕組み」が requestIdleCallback です。
基本の使い方と「IdleDeadline」オブジェクト
一番シンプルな書き方
requestIdleCallback((deadline) => {
console.log("ブラウザがヒマになったので呼ばれました");
});
JavaScriptrequestIdleCallback に渡すのは、
「あとで呼んでほしい関数」 です。
この関数は、ブラウザが「今ちょっと余裕あるな」と判断したタイミングで呼ばれます。
コールバックの引数 deadline が重要です。
これは IdleDeadline というオブジェクトで、
「どれくらい時間の余裕が残っているか」を教えてくれます。
deadline.timeRemaining() で「残り時間」を知る
deadline.timeRemaining() を呼ぶと、
「このアイドル時間の中で、あと何ミリ秒くらい使えそうか」 が分かります。
requestIdleCallback((deadline) => {
console.log("残り時間:", deadline.timeRemaining());
});
JavaScriptこの値はミリ秒で、
例えば 10〜20ms くらいの値が返ってくることが多いです(環境による)。
この「残り時間」を見ながら、
「今のスキにどこまで処理を進めるか」 を決めるのが、requestIdleCallback の肝です。
deadline.didTimeout で「締め切り超えたかどうか」が分かる
requestIdleCallback には第 2 引数で「タイムアウト」を指定できます。
requestIdleCallback(
(deadline) => {
if (deadline.didTimeout) {
console.log("締め切りを過ぎたので、とにかく実行された");
}
},
{ timeout: 2000 }
);
JavaScripttimeout: 2000 を指定すると、
「2 秒以内にヒマな時間が見つからなかった場合、
ヒマじゃなくてもとにかく呼ぶ」という挙動になります。
deadline.didTimeout が true のときは、
「もう待てないから実行された」と理解できます。
具体例:大きな配列を「ヒマなときに少しずつ処理する」
一気にやると重い処理を、小分けにして実行する
例えば、1 万件のデータを処理する必要があるとします。
const items = Array.from({ length: 10000 }, (_, i) => i);
JavaScriptこれを一気にループすると、
メインスレッドを長時間占有してしまい、
UI がカクついたり、入力が詰まったりします。
そこで、requestIdleCallback を使って、
「ブラウザがヒマなときに、少しずつ処理する」 という戦略が取れます。
const items = Array.from({ length: 10000 }, (_, i) => i);
let index = 0;
function work(deadline) {
while (deadline.timeRemaining() > 0 && index < items.length) {
const item = items[index];
// ここで item を処理する(重くない単位に分割)
index++;
}
if (index < items.length) {
requestIdleCallback(work);
} else {
console.log("すべての処理が完了しました");
}
}
requestIdleCallback(work);
JavaScriptここでやっていることを丁寧に言うと、
ブラウザがヒマになったら work が呼ばれるdeadline.timeRemaining() が 0 になるまで、ループで少しずつ処理する
まだ残りがあるなら、次のアイドル時間にまた work を予約する
という流れです。
これにより、
ユーザーの操作や描画を邪魔せずに
大きな処理を「ちょっとずつ」進められます。
「今すぐじゃなくていい処理」を見極める感覚
requestAnimationFrame と requestIdleCallback の役割の違い
requestAnimationFrame
「画面を描画する直前に呼んでほしい」
→ アニメーションや UI 更新向き(ユーザーが“今”見ているもの)
requestIdleCallback
「ユーザーの体感に影響しないタイミングで呼んでほしい」
→ ログ送信、事前計算、キャッシュ作成など(“裏方の仕事”)
つまり、
ユーザーが今見ているものを動かす → rAF
ユーザーが気づかなくてもいい裏方処理 → rIC(requestIdleCallback)
という分担になります。
どんな処理を idle に回すといいか
例えば、こんなものは requestIdleCallback 向きです。
画面表示には直接関係ないログの送信
次の画面で使うかもしれないデータの事前フェッチ
重くないけど件数が多い集計処理
フォーム入力後の「サジェスト候補の事前計算」
共通しているのは、
「今すぐやらなくても、少し遅れてもユーザーが困らない」 という点です。
対応状況とフォールバックの考え方
すべてのブラウザが対応しているわけではない
requestIdleCallback は便利ですが、
まだすべてのブラウザで完全に標準というわけではありません。
そのため、実務では
対応していれば requestIdleCallback を使う
なければ setTimeout などで代替する
というフォールバックを書くことが多いです。
const ric =
window.requestIdleCallback ||
function (cb) {
return setTimeout(() => cb({ timeRemaining: () => 0, didTimeout: true }), 0);
};
const cancelRic =
window.cancelIdleCallback ||
function (id) {
clearTimeout(id);
};
JavaScriptこうしておけば、ric を requestIdleCallback の代わりに使っても、
非対応ブラウザでは「とりあえずすぐ実行」に近い動きになります。
初心者として requestIdleCallback で本当に掴んでほしいこと
requestIdleCallback は「ブラウザがヒマなときにやってもらう処理」を予約する仕組み
コールバックの引数 deadline から「残り時間(timeRemaining)」と「締め切り超えたか(didTimeout)」が分かる
大きな処理を「ヒマなときに少しずつ進める」ことで、UI のカクつきを減らせる
requestAnimationFrame は「今見えているもののため」、requestIdleCallback は「裏方のため」という役割分担
対応していないブラウザもあるので、フォールバックを用意することが多い
まずは、
大きな配列を一気に処理するコード
→ それを requestIdleCallback で「小分け処理」に書き換えてみる
という練習をしてみると、
「ユーザーの体感を壊さずに重い処理をこなす」という感覚が、かなりリアルに掴めるはずです。
