JavaScriptでのイベント制御手法として、デバウンス( debounce)とスロットル( throttle)があります。これらの手法は、resize、scroll、入力検証などの操作において、関数の呼び出し頻度を制限し、ブラウザの負荷を軽減します。
### デバウンス( debounce)
デバウンスは、一定時間内にイベントが連続してトリガーされても、そのイベントが停止してから指定した時間が経過した後にのみ関数を実行します。この手法により、イベントが発生している間は関数を呼び出しません。例えば、scrollイベントが1000ミリ秒以内に発生した場合、関数は実行されません。発生が止まって1000ミリ秒後にのみ関数が実行されます。
以下に簡単なデバウンスの実装例を示します。
### スロットル( throttle)
スロットルは、一定時間内にイベントがトリガーされても、その期間内に1回のみ関数を実行します。この手法は、関数の呼び出しを一定間隔で制限します。
スロットルの実装は、主に2つの方法があります:タイムスタンプとタイマー。以下にそれぞれの方法を示します。
### 概要
- **デバウンス**:複数回の操作を1回にまとめます。指定された時間が経過した後にのみ関数を実行します。
- **スロットル**:一定时间内に1回のみ関数を実行します。
- **違い**:スロットルは一定时间内に必ず1回関数を実行しますが、デバウンスは操作が停止した後にのみ関数を実行します。無限スクロールのようなシナリオでは、ユーザーがスクロールしている間も定期的にAjaxリクエストを送信する必要があるため、スロットルが適しています。
// デバウンス
function debounce(func, wait = 0) {
if (typeof func !== 'function') {
throw new TypeError('関数を渡す必要があります');
}
let timeoutId = null;
let returnValue;
return function() {
const context = this;
const args = arguments;
if (timeoutId) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
returnValue = func.apply(context, args);
}, wait);
return returnValue;
};
}
// 関数
function handle() {
console.log(Math.random());
}
// スクロールイベントにデバウンスを適用
window.addEventListener('scroll', debounce(handle, 1000));
// タイムスタンプを使用したスロットル
function throttle(func, delay) {
let lastExecuted = 0;
return function() {
const now = Date.now();
if (now - lastExecuted >= delay) {
func.apply(this, arguments);
lastExecuted = now;
}
};
}
function handle() {
console.log(Math.random());
}
window.addEventListener('scroll', throttle(handle, 1000));
// タイマーを使用したスロットル
function throttle(func, delay) {
let timer = null;
return function() {
const context = this;
const args = arguments;
if (!timer) {
timer = setTimeout(() => {
func.apply(context, args);
timer = null;
}, delay);
}
};
}
function handle() {
console.log(Math.random());
}
window.addEventListener('scroll', throttle(handle, 1000));
// タイムスタンプとタイマーを組み合わせたスロットル
function throttle(func, delay) {
let timer = null;
let startTime = Date.now();
return function() {
const now = Date.now();
const remaining = delay - (now - startTime);
const context = this;
const args = arguments;
clearTimeout(timer);
if (remaining <= 0) {
func.apply(context, args);
startTime = Date.now();
} else {
timer = setTimeout(() => {
func.apply(context, args);
}, remaining);
}
};
}
function handle() {
console.log(Math.random());
}
window.addEventListener('scroll', throttle(handle, 1000));