JavaScript の世には デバウンス(debounce) と スロットル(throttle) という便利な手法があることを最近知りました。
残念ながら弊社エンジニアは誰も知らない可能性が高いので、メモして共有するため記事にしました。
デバウンスの記事は先に書いてます。
スロットル (throttle)
同じイベントが連続して発火するような状況で、発火した回数分処理を実行すると負荷が高くなってしまう場合に、最初のイベント発火から指定した秒数を経過するまで、次のイベント処理を遅延させる手法です。
デバウンスと似てますが、真逆という訳でもなさそうですね
デバウンスは「指定秒数待ってからイベント処理を実行する。その指定秒数内のイベントは停止される」のに対して、スロットルは「イベント処理を実行してから指定秒数経過するまでは次のイベント処理を遅延させる」という感じですね。デバウンスのイベント処理を停止させるのとはちょっと違います。
(※複数回イベント処理が実行された場合、最後のイベント処理以外は停止になるようですが)
雑なサンプルコード
'test-throttle' という id を持つボタンがあり、クリック後に 'Click Event Called' という文字列と現在日時とコンソールに出力する。その後1秒経過する前に再度クリックイベントが発火した場合は、1秒経過するまでは遅延される。
/**
* 無名関数の実行を制限し、指定間隔(ms)毎に一回のみ実行
*
* @param {Function} anonymousFunction - スロットルされる無名関数
* @param {number} limit - 実行間隔(ms)
* @returns {Function}
*/
function throttle(anonymousFunction, limit)
{
let lastFunctionTimerId;
let lastExecute;
return function() {
const context = this;
const args = arguments;
// 最初の1回はすぐ実行
if (!lastExecute) {
anonymousFunction.apply(context, args);
lastExecute = Date.now();
return;
}
clearTimeout(lastFunctionTimerId);
lastFunctionTimerId = setTimeout(function() {
anonymousFunction.apply(context, args);
lastExecute = Date.now();
// 1秒以上経過している場合は即実行、そうでなければ残り時間経過後に実行
}, limit - (Date.now() - lastExecute));
}
}
/**
* 'Click Event Called' という文字列と現在日時を console に出力し、1秒間は次のイベントを受け付けない
*/
const clickEvent = throttle(function() {
console.log('Click Event Called');
console.log(new Date());
}, 1000);
/**
* ページロード後、id が test-throttle の要素に対して click イベントリスナーを追加
*/
window.addEventListener('load', function() {
document.getElementById('test-throttle').addEventListener('click', clickEvent);
});
確かに連打しまくっても1秒毎にしか実行されてない模様
感想
底辺エンジニアなのでスロットルのよい使い道がイマイチ思いつかない…
デバウンスと比べて、ちょっと使いづらい気がします