Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
111
Help us understand the problem. What is going on with this article?

More than 3 years have passed since last update.

@waterada

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

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関連の記事

111
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
111
Help us understand the problem. What is going on with this article?