JavaScript | Web API:タイマー・スケジューリング - requestIdleCallback

JavaScript JavaScript
スポンサーリンク

requestIdleCallback は「ブラウザがヒマなときにやってもらう雑用係」

requestIdleCallback は、
「今すぐじゃなくて、ブラウザがヒマになったタイミングでやってほしい処理」を予約するための関数 です。

ユーザーの操作に直結する処理(クリックへの反応、入力の反映など)は、できるだけ即座に実行したいですよね。
一方で、

ログの送信
重くないけど地味に時間がかかる集計
次に使うかもしれないデータの事前計算

みたいな「急ぎじゃない処理」は、
ブラウザがヒマなときに回してもらったほうが、体感が軽くなります。

その「ヒマなときにやってもらう仕組み」が requestIdleCallback です。


基本の使い方と「IdleDeadline」オブジェクト

一番シンプルな書き方

requestIdleCallback((deadline) => {
  console.log("ブラウザがヒマになったので呼ばれました");
});
JavaScript

requestIdleCallback に渡すのは、
「あとで呼んでほしい関数」 です。
この関数は、ブラウザが「今ちょっと余裕あるな」と判断したタイミングで呼ばれます。

コールバックの引数 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 }
);
JavaScript

timeout: 2000 を指定すると、
「2 秒以内にヒマな時間が見つからなかった場合、
ヒマじゃなくてもとにかく呼ぶ」という挙動になります。

deadline.didTimeouttrue のときは、
「もう待てないから実行された」と理解できます。


具体例:大きな配列を「ヒマなときに少しずつ処理する」

一気にやると重い処理を、小分けにして実行する

例えば、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

こうしておけば、
ricrequestIdleCallback の代わりに使っても、
非対応ブラウザでは「とりあえずすぐ実行」に近い動きになります。


初心者として requestIdleCallback で本当に掴んでほしいこと

requestIdleCallback は「ブラウザがヒマなときにやってもらう処理」を予約する仕組み
コールバックの引数 deadline から「残り時間(timeRemaining)」と「締め切り超えたか(didTimeout)」が分かる
大きな処理を「ヒマなときに少しずつ進める」ことで、UI のカクつきを減らせる
requestAnimationFrame は「今見えているもののため」、requestIdleCallback は「裏方のため」という役割分担
対応していないブラウザもあるので、フォールバックを用意することが多い

まずは、

大きな配列を一気に処理するコード
→ それを requestIdleCallback で「小分け処理」に書き換えてみる

という練習をしてみると、
「ユーザーの体感を壊さずに重い処理をこなす」という感覚が、かなりリアルに掴めるはずです。

タイトルとURLをコピーしました