224
143

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

lodash の debounce や throttle で簡単に負荷対策

Last updated at Posted at 2018-07-01

JavaScript を使っているなら lodash は大変便利なのですが、関数が多すぎてどれ使ったらいいのか解りづらいのが難点です。

ここではその中でも連続する呼び出しを無視してくれる debouncethrottle という負荷対策用の関数を紹介します。また、この2つの似た関数がどう違うのかも説明します。

連続する呼び出しを無視したい、とはどういうことか

たとえば、mouse move イベントはマウスの座標が動くたびにすごい頻度で発生します。これに応じて画面を同期させたり、サーバに問い合わせしてしまうと大変なので一般的には0.2秒とかマウスが止まったら同期や問い合わせが走るように実装するかと思います。

別の例でいえば、textbox のインクリメンタルサーチ実装で、文字打つたびにサーバ問い合わせしたら大変なので、入力がある程度止まった時点で問い合わせするのが一般的です。

この処理をすごく簡単に実装できるのが debounce です。

debounce の使い方

元の処理
$panel.on('mousemove', function () {
  // 画面同期 or サーバ問い合わせ (ただし高頻度で呼ばれる)
});

これを下記のように _.debounce(関数, wait時間) で囲むだけで実現できます。

マウスが動いてる限りは呼ばない
$panel.on('mousemove', _.debounce(function () {
  // 画面同期 or サーバ問い合わせ (ただし 0.2 秒動きが止まったら呼ばれる)
}, 200));

また、下記のように maxWait を指定することで、マウスが動いてても一定秒に 1 回は最低限呼ばれるようにもできます。

1秒に1回は最低呼ばれるように
$panel.on('mousemove', _.debounce(function () {
  // 画面同期 or サーバ問い合わせ
}, 200, { maxWait: 1000 }));

debounce の注意点

_.debounce() は自身では実行せず、関数を返すということに注意してください。上記のようにコールバックをラップするのにはちょうど良いですが、通常処理の中に setTimeout() 的なノリで記述すると実行されなくて悩むことになるかも。
(もし発火させたいなら、_.debounce(~)() のように末尾に () を付ければよいでしょう。)

似た関数 throttle があるけど?

throttledebounce と似ていますが、使い道が若干異なります。throttle は、一定時間に1度しか実行されないようにするためのものです。

たとえば、データに変更があるたびに定期的にサーバへと同期させたいとします。とはいえ、スペック的に1秒に1回以上は同期したくないという場合に throttle の出番となります。

もしこれを、debounce でやってしまうと、更新がある限り永遠にサーバに同期されません。maxWait を指定した場合はほぼ同じ動きにはなりますが、throttle では最初に1度実行されるという点が大きな違いとなります。

throttle は、まず1回実行し、その後一定期間、呼び出しを監視し、呼び出しがあれば最後の呼び出しだけを実行する(呼び出しがなければその後は何もしない)というものです。最初に1回実行するので後続呼び出しが無い場合も効率的です。

こういう動きになります
0s 呼び出し1   呼び出し1 を実行する
   ↓
   呼び出し2(実行されない)
   ↓
   呼び出し3(実行されない)
   ↓
   呼び出し4
   ↓
1s            呼び出し4 を実行する

debounce が一定時間止まったら実行させる、という考え方なのに対して、throttle は一定時間に1回というペースを守らせるという考え方です。

throttle の使い方

元の処理
function onChangeData (newData) { // データが変更されるたびに呼ばれる
  // サーバへの同期処理
}

これを下記のように _.throttle(関数, wait時間) で囲むだけで実現できます。

1秒に1回というペースを守らせる
var _changeData = _.throttle(function (newData) {
  // サーバへの同期処理
}, 1000);

function onChangeData (newData) { // データが変更されるたびに呼ばれる
  _changeData();
}

まとめ

  • debounce: 一定時間止まったら実行させる。
  • throttle: 一定時間に1回というペースを守らせる。

lodash関連の記事

224
143
4

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
224
143

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?