以下の内容はhttps://uga-box.hatenablog.com/entry/2025/04/21/000000より取得しました。


【Web】requestAnimationFrameで1frameごとの処理を行う

Webアプリケーションのある処理によって画面の更新頻度が多く、CPUが弱いマシンだとフリーズしてしまう問題が起きた

これを解決するために、デバウンスを実行しようと考えた時、遅延方法として requestAnimationFrame がいいのではないかと聞いた

requestAnimationFrame をよく知らなかったので調べた

developer.mozilla.org

requestAnimationFrame とは?

window.requestAnimationFrame() は、ブラウザのレンダリングサイクルに合わせてアニメーションを実行するためのJavaScriptメソッド

一般的に次のように使用する

javascriptfunction animate(timestamp) {
  // アニメーション処理
  // timestampはコールバック実行時の時間(ミリ秒)
  
  // 次のフレームをリクエスト
  requestAnimationFrame(animate);
}

// アニメーション開始
requestAnimationFrame(animate);

requestAnimationFrame の主な特徴

1. ブラウザの描画サイクルに最適化

requestAnimationFrame はブラウザの描画タイミングに合わせて実行されるため、フレームの境界で処理が行われ、画面の更新がスムーズになる

通常のディスプレイでは60FPS(16.7ミリ秒ごと)に合わせて実行されるが、高リフレッシュレートのディスプレイにも自動的に対応している

2. バッテリー効率の向上

タブがバックグラウンドになった場合や画面外にスクロールされた場合、requestAnimationFrame の実行は自動的に抑制される

これにより無駄な処理を減らし、特にモバイルデバイスでのバッテリー寿命を延ばせる

3. 正確なタイムスタンプの提供

コールバック関数には高精度のタイムスタンプが渡され、これを利用して時間ベースのアニメーションを実装できる

バイスの処理速度に関わらず一定の速度でアニメーションを実行するのに役立つ

従来の方法を使用する場合の問題点

setTimeout や setInterval などの従来のタイマー関数を使ったアニメーション実装には、以下のような問題がある

1. パフォーマンスの低下

  • 画面更新との非同期: ブラウザのレンダリングサイクルと同期せず、フレームの途中で更新が実行されることがある
  • ティアリング: 画面の一部だけが更新された状態で表示される「画面の裂け」が発生
  • フレームスキップ: 処理が間に合わずフレームが飛ぶことによる不自然な動き

2. 電力効率の悪化

  • バックグラウンドタブや非表示エリアでも処理が継続する
  • モバイルデバイスでのバッテリー消費が増加
  • リソースの無駄遣いになる

3. タイミングの不正確さ

// 悪い例: setInterval を使ったアニメーション
setInterval(() => {
  position += 5; // 固定量の移動
  box.style.transform = `translateX(${position}px)`;
}, 16.7); // 約60FPSを意図

上記のようなコードでは:

  • 実際の間隔は不正確(最小間隔の保証のみ)
  • 処理負荷が高い場合に遅延が蓄積
  • バイス性能によってアニメーション速度が変わる

実践的な使用例: 時間ベースのアニメーション

requestAnimationFrame と経過時間を使った正しいアニメーション実装例:

let boxElement = document.querySelector('.box');
let start = null;

function moveBox(timestamp) {
  if (!start) start = timestamp;
  
  // 経過時間を計算
  const elapsed = timestamp - start;
  
  // 経過時間に基づいて位置を計算(5秒で300px移動)
  const position = Math.min(elapsed / 5000 * 300, 300);
  
  // 要素のスタイルを更新
  boxElement.style.transform = `translateX(${position}px)`;
  
  // アニメーションが終了していなければ続行
  if (position < 300) {
    requestAnimationFrame(moveBox);
  }
}

// アニメーション開始
requestAnimationFrame(moveBox);

この方法では、どのデバイスでも同じ期間(5秒)で動作が完了する




以上の内容はhttps://uga-box.hatenablog.com/entry/2025/04/21/000000より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14