こんにちは!フロントエンドの現場を渡り歩いているチーフアーキテクトの私です。
Webサイトを作っていて、「なんだか画面がカクつく」「ボタンを押してもワンテンポ遅れて反応する」なんてモヤモヤした経験、ありませんか?
特にスマホでアクセスしたとき、スクロールが重かったりすると、それだけでユーザーはページをそっと閉じちゃいますよね。「私のコード、何か間違っているのかな…」と不安になるかもしれませんが、大丈夫ですよ!その悩み、実はWebブラウザの「お仕事の仕組み」を知るだけで、スルスルと解決の糸口が見えてきます。
今回は、そんな重い処理をこっそり裏で片付けてくれる、ちょっと職人肌で頼れる機能`requestIdleCallback`について、一緒に優しく紐解いていきましょう!
—
1. Webブラウザは「超多忙なワンオペ店員さん」
まず、ブラウザが裏側でどうやって働いているのか、身近な例えでお話ししますね。
Webブラウザのメインスレッド(中心となって動く場所)は、まるで「町の小さな定食屋のワンオペ店員さん」です。
この店員さん、1人でこんな仕事を全部こなしています。
- お客さんの注文を聞く(クリックやタップのイベント処理)
- 料理を作る(HTMLを読み込んで、見た目を組み立てる=レンダリング)
- 配膳する・お店を掃除する(アニメーションを描画する)
想像してみてください。この店員さんが、めちゃくちゃ面倒くさい「大量の仕込み(重いJavaScriptの計算やデータ送信など)」を、お客さんが目の前でメニューを見ている最中に始めちゃったらどうなります?
「お水ください!」と言われても、「ちょっと待って!今キャベツ千切り中だから!」と無視することになりますよね。これが、Webサイトが「カクつく」「固まる」正体です。
じゃあ、どうすればいいでしょう?
そう、「お客さんがメニューを選んで迷っている『ちょっとした隙間時間(アイドル時間)』に、こっそり仕込みを進めればいい」んです。
この「隙間時間を見つけて上手に仕事をする」ための魔法の呪文が、`requestIdleCallback` なのです。
—
2. `requestIdleCallback` ってなに?
`requestIdleCallback` は、ブラウザにこうお願いするためのAPIです。
> 「ねえブラウザさん、今からちょっと暇になりそうなタイミング(アイドル時間)が来たら、このバックグラウンドの作業をこっそりやっておいてくれない?」
ブラウザは1秒間に約60回(60fps)、画面をパラパラ漫画のように描き替えるため必死です。1コマあたり使える時間は、わずか「約16ミリ秒」しかありません。
この16ミリ秒の中に、アニメーションの描画やユーザーのクリック処理が終わると、「あ、次のフレームまで数ミリ秒だけ余裕ができたな」という隙間(アイドル時間)が生まれます。
`requestIdleCallback` は、その隙間をピタッと見計らって、ユーザーの操作を邪魔しないように低優先度のタスクをこっそり実行してくれるんです。なんて空気が読める子なんでしょう!
—
3. 実際のコードを見てみよう
「理屈は分かったけど、書き方は難しそう…」と思いました? 大丈夫です、基本の形はとてもシンプルですよ。
例えば、ユーザーには見えないところで「アクセス解析のデータをサーバーにこっそり送る」という処理を考えてみましょう。急ぎではないけれど、やっておかないといけないお仕事ですね。
// ブラウザがヒマになったら実行してほしい関数
function sendAnalyticsData(deadline) {
// deadline.timeRemaining() で「あと何ミリ秒くらいヒマか」が分かります
console.log(`ブラウザの残り休憩時間: ${deadline.timeRemaining()}ミリ秒`);
// まだヒマな時間が残っていて、かつ、やるべき仕事がある間ループする
while (deadline.timeRemaining() > 0 && tasksQueue.length > 0) {
const task = tasksQueue.shift(); // リストから一つ仕事を取り出す
task(); // 仕事を実行!
}
// もし仕事が残っていたら、次のヒマな時間に持ち越し!
if (tasksQueue.length > 0) {
requestIdleCallback(sendAnalyticsData);
}
}
// やりたい仕事のリスト(キュー)
const tasksQueue = [
() => console.log(‘アクセスログ1送信完了’),
() => console.log(‘アクセスログ2送信完了’),
() => console.log(‘アクセスログ3送信完了’),
];
// ブラウザにお願いする!
// 「ねえ、ヒマになったら sendAnalyticsData 動かしてね」
requestIdleCallback(sendAnalyticsData);
💡 ここがポイント!
コードに出てくる `deadline.timeRemaining()` というのがミソです。これは「今、あと何ミリ秒くらいブラウザは手があいていますよ」という残り時間を教えてくれます。
もしユーザーが突然激しくマウスを動かしたりしたら、ブラウザは「あ、忙しくなったから休憩終わり!」と、この残り時間を `0` にします。そうすると、コード側も「おっと、じゃあ続きはまた今度ね」と安全に中断できるわけです。空気を読むって素晴らしい!
—
4. 使うときの「ちょっとした注意点」
万能に見える `requestIdleCallback` ですが、実務で使うときはいくつか優しくフォローしておきたいポイントがあります。
1. 画面の見た目を変える処理は入れない
- DOMをいじってレイアウトを変えたりする処理をアイドル時間に入れ込むと、画面がガタつく原因になります。あくまで「画面に直接関係ない裏側のデータ処理(ログ送信、事前キャッシュ、重いデータの事前計算など)」に使いましょう。
2. Safariへの配慮(フォールバック)
- 実は、長らくSafariがこの `requestIdleCallback` をネイティブでサポートしていませんでした(※最近のバージョンでは対応が進んでいますが)。そのため、現場では以下のように「もし使えなかったら、`setTimeout` で代用する」というおまじない(ポリフィル的な考え方)を書いておくのがプロの技です。
// requestIdleCallbackが使えないブラウザのための安全ネット
const safeRequestIdleCallback = window.requestIdleCallback || function (callback) {
const start = Date.now();
return setTimeout(function () {
callback({
didTimeout: false,
timeRemaining: function () {
return Math.max(0, 50 – (Date.now() – start));
}
});
}, 1);
};
こういうちょっとした優しさをコードに仕込んでおくと、どんな環境で見ているユーザーに対しても安定したパフォーマンスを届けることができますよ。
—
さいごに
Webブラウザのレンダリングやパフォーマンス最適化と聞くと、なんだか冷たくて難しい壁のように感じるかもしれませんが、本質はとてもシンプルです。
「ユーザーの快適な体験(お買い物や閲覧)を一番大事にして、裏方の地味な仕事は店員さんがヒマな隙を狙ってこっそり片付ける」
この思いやりをコードで表現するための素敵な道具が `requestIdleCallback` です。ぜひ、あなたのWebサイトのちょっとした裏方処理に取り入れてみてくださいね。あなたの書いたコードが、これまで以上に軽やかに、優しく動くようになりますよ!

コメント