JavaScriptでの多発するイベントの間引き処理

こんにちは、つみきのフロントエンドエンジニアの佐藤です。

JavaScript でブラウザの scrollresize イベントで何か処理をさせる場合に、そのままだとイベントが頻発し、ブラウザや端末に負荷をかけてしまいます。

今回はこれらの処理を間引く代表的な手法の throttle と debounce について紹介してみたいと思います。

イベント頻発

例えば、 resize イベントに対してそのままイベントハンドラを設定してしまうと、下記例のように何度も処理が実行されます。

ウィンドウのサイズを変更して試してみてください。

http://sugarshin.github.io/throttle-debounce-demo/

throttle

throttle は、最初のイベント発生から、何度連続してイベントが発生しても処理はせず、指定時間経過後に規則的に処理を実行するようなイメージです。

実装例としては以下のような感じでしょうか。

var throttleFunc = (function() {

  // 間引き間隔
  var interval = 500;

  // 最後に実行した時間
  var lastTime = new Date().getTime() - interval

  return function() {

    // 最後に実行した時間から間引きたい時間経過していたら実行
    if ((lastTime + interval) <= new Date().getTime()) {
      lastTime = new Date().getTime();
      // 処理 ...
    }
  };
})();

最後に実行した時間から、指定時間経過していたら実行される関数を即時関数で返しています。

例としては以下のようになります。ウィンドウのサイズを変更して試してみてください。

http://sugarshin.github.io/throttle-debounce-demo/throttle/

debounce

debounce はイベント発生後に、指定時間内に同じイベントが発生すると処理は実行されず、発生しなければ処理を実行するというような感じです。

例としては以下のような感じですかね。

var debounceFunc = (function() {

  // 停止させたい間隔
  var interval = 500;
  var timer;

  return function() {
    clearTimeout(timer);
    timer = setTimeout(function() {
      // 処理 ...
    }, interval);
  };
})();

こちらも例を用意しました。

http://sugarshin.github.io/throttle-debounce-demo/debounce/

どちらを使用するかは実現したいものによって変わってくるかと思います。場合によってはこれらの間引き処理はしないほうが適切な場合もあるでしょう。


実際にこれらを実装する際に便利なライブラリやプラグインをいくつか紹介したいと思います。

jquery-throttle-debounce

jQuery を利用する場合はこちらが有名ですね。 jQuery プラグインとして利用できます。

https://github.com/cowboy/jquery-throttle-debounce

$.throttle()

throttle の利用例としては以下のような感じです。

var func = function() {
  // 処理 ...
};

$(window).on('resize', $.throttle(500, func));

$.throttle() は間引き処理を施した関数を返してくれます。

第1引数に間引き間隔時間、第2引数に実際の関数を渡してあげます。

また、第2引数に true を渡すと、最後の判定が走ったあとイベントが止まったら処理は実行されません。

$.throttle(500, true, func);

$.debounce()

var func = function() {
  // 処理 ...
};

$(window).on('resize', $.debounce(500, func));

$.debounce() も使い方はほぼ同じです。

第2引数に true を渡すと、イベント発生直後に処理を実行してくれます。

$.debounce(500, true, func);

Underscore.js

Underscore.js でも同等なメソッドが用意されていますね。

http://underscorejs.org/#throttle

http://underscorejs.org/#debounce

これらも間引き処理を施した関数を返してくれます。

_.throttle(function, wait);

_.debounce(function, wait);

まとめ

頻発する可能性のあるイベントに、重い処理を登録する際には、利用してみるといいのではないかと思います。

この記事を読んで、自分もつみきで働きたい!と思った方は、こちら

つみきの採用情報