1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

requestAnimationFrameや イベント間引き (throttle/debounce)について

Posted at
  • requestAnimationFrame とは、ブラウザが最適なタイミング(モニターのリフレッシュレート等に合わせた描画タイミング)で呼び出すコールバックを登録する仕組みです。リアルタイム性が求められるアニメーションや頻繁な画面再描画を行う際に、単純に setTimeoutmousemove のたびに再描画するよりパフォーマンスが向上しやすい利点があります。
  • イベント間引き (throttle / debounce) とは、マウス移動やスクロールなど高頻度で発火するイベントを、そのまま処理し続けると負荷が高いので、一定のルールで間引きするテクニックです。
    • throttle: 一定時間内に複数回イベントが発生しても、最初の1回だけ処理し、その後は無視する or 次回実行まで待つ。
    • debounce: あるイベントが連続で発生する場合、最後の1回だけや、しばらく間が空いたところで処理する。

requestAnimationFrame とは

  • ブラウザには window.requestAnimationFrame(callback) という関数があり、連続したアニメーション描画の際に callback を呼び出してくれます。
  • 従来は setTimeoutsetInterval を使って 16ms くらいの間隔でアニメーションを行う手法が使われていましたが、requestAnimationFrame を使うとブラウザのリフレッシュタイミングに合わせて効率よくコールバックが実行されます。
  • コード例(マウス移動などではなく、単純にアニメーションする例):
// アニメーションしたいオブジェクトの位置
let x = 0;

// アニメーションループ関数
function animate() {
  // 何らかの描画処理
  const elem = document.getElementById('box');
  elem.style.transform = `translateX(${x}px)`;
  
  // 値を更新して次フレーム
  x += 1;
  requestAnimationFrame(animate);
}

// 実行開始
requestAnimationFrame(animate);
  • 上記のように、ループの最後で再度 requestAnimationFrame(animate) を呼ぶことで連続したアニメーションを実行できます。

ドラッグなどへの応用

  • マウス移動のたびに chart.invalidate() を呼ぶと処理が激しくなる場合があります。そこでマウス位置を更新しつつ、実際の再描画は requestAnimationFrame 内でまとめて行う、といった手法がよく使われます。

イベント間引き (throttle / debounce) とは

throttle(スロットル)

  • 一定時間(例: 100ms)ごとに、1回だけイベント処理する方法。
  • 例えばマウス移動が毎秒 100 回あっても、100ms ごとに 1 回しか処理しないので、最大で毎秒 10 回に抑えられる。
  • 例:
function throttle(func, limit) {
  let inThrottle = false;
  return function(...args) {
    if (!inThrottle) {
      func.apply(this, args);
      inThrottle = true;
      setTimeout(() => inThrottle = false, limit);
    }
  };
}

// 使い方
window.addEventListener('scroll', throttle(function() {
  console.log('スクロールイベント処理!');
}, 200));

debounce(デバウンス)

  • イベントが止んでから一定時間後に 1 回だけ実行する方法。
  • 例えばテキスト入力中にイベントが連続発火しても、入力完了してから 300ms 後に処理する、といった使い方をする。
  • 例:
function debounce(func, wait) {
  let timeout;
  return function(...args) {
    clearTimeout(timeout);
    timeout = setTimeout(() => func.apply(this, args), wait);
  };
}

// 使い方
const onResize = debounce(function() {
  console.log('リサイズ完了後に処理!');
}, 300);

window.addEventListener('resize', onResize);

まとめ

  • requestAnimationFrame はアニメーションや頻繁な再描画を効率よく行うための仕組み。
  • イベント間引き (throttle / debounce) は大量発生するイベントを抑制し、パフォーマンスを確保したいときに使う手法。
  • グラフのドラッグやスクロールなど、イベントが非常に高頻度で発生するケースでは、これらの仕組みを組み合わせると動作が滑らかになり、CPU 負荷も低減できます。
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?