レッスンに戻る

デバウンスデコレータ

重要度: 5

debounce(f, ms) デコレータの結果は、fへの呼び出しを、msミリ秒の非アクティブ期間(呼び出しなし、「クールダウン期間」)になるまで一時停止し、その後、最新の引数でfを一度呼び出すラッパーです。

言い換えると、debounceは「電話を受け付け」、静かな状態がmsミリ秒続くまで待つ秘書のようなものです。そして、そのとき初めて最新の通話情報を「上司」(実際のf)に転送します。

例えば、関数fがあり、それをf = debounce(f, 1000)で置き換えたとします。

その後、ラップされた関数が0ms、200ms、500msで呼び出され、その後呼び出しがない場合、実際のfは1500msに一度だけ呼び出されます。つまり、最後の呼び出しから1000msのクールダウン期間後です。

…そして、最後の呼び出しの引数を受け取ります。他の呼び出しは無視されます。

そのためのコードを次に示します(Lodashライブラリのdebounceデコレータを使用しています)。

let f = _.debounce(alert, 1000);

f("a");
setTimeout( () => f("b"), 200);
setTimeout( () => f("c"), 500);
// debounced function waits 1000ms after the last call and then runs: alert("c")

では、実用的な例を見てみましょう。ユーザーが何かを入力し、入力の完了時にサーバーにリクエストを送信したいとします。

入力された文字ごとにリクエストを送信しても意味がありません。代わりに待機してから、結果全体を処理したいと考えています。

ウェブブラウザでは、イベントハンドラ(入力フィールドの変更ごとに呼び出される関数)を設定できます。通常、イベントハンドラは、入力されたキーごとに非常に頻繁に呼び出されます。しかし、それを1000msでdebounceすると、最後の入力から1000ms後、一度だけ呼び出されます。

このライブ例では、ハンドラは結果を下のボックスに入力します。試してみてください。

ご覧のとおり、2番目の入力はデバウンスされた関数を呼び出すため、その内容は最後の入力から1000ms後に処理されます。

そのため、debounceは、キー押下、マウスの動き、その他のイベントシーケンスを処理するのに最適な方法です。

最後の呼び出し後、指定された時間待機し、結果を処理できる関数を実行します。

課題は、debounceデコレータを実装することです。

ヒント:少し考えれば、ほんの数行です :)

テストを含むサンドボックスを開きます。

function debounce(func, ms) {
  let timeout;
  return function() {
    clearTimeout(timeout);
    timeout = setTimeout(() => func.apply(this, arguments), ms);
  };
}

debounceへの呼び出しは、ラッパーを返します。呼び出されると、指定されたms後に元の関数の呼び出しをスケジュールし、前のそのようなタイムアウトをキャンセルします。

サンドボックスでテストを含む解答を開きます。