JavaScriptでのデバウンスとスロットルの概念と実装方法について説明します。
デバウンス
デバウンスは、連続して発生するイベントに対して一定時間経過後に1回だけ処理を実行する技術です。例えば、Reactコンポーネント内で検索機能を実装する際に、ユーザーが入力フィールドに文字を入力するたびにAPIを呼び出す場合、この手法が効果的です。
以下は、シンプルなデバウンス関数の実装例です:
const debounce = (callback, delay) => {
let timer;
return function(...args) {
const context = this;
clearTimeout(timer);
timer = setTimeout(() => callback.apply(context, args), delay);
};
};
class SearchComponent extends Component {
state = { query: "" };
handleInputChange = debounce((e) => {
this.setState({ query: e.target.value });
}, 500);
render() {
return (
<div>
<input type="text" onInput={(e) => this.handleInputChange(e)} />
<p>{this.state.query}</p>
</div>
);
}
}
精密デバウンス
精密デバウンスでは、初回の実行を即座に行うかどうかを制御できます。これにはimmediateフラグを使用します。
const preciseDebounce = (fn, wait, immediate = false) => {
let timeoutId;
return function(...args) {
const context = this;
if (timeoutId) clearTimeout(timeoutId);
if (immediate && !timeoutId) fn.apply(context, args);
timeoutId = setTimeout(() => {
timeoutId = null;
if (!immediate) fn.apply(context, args);
}, wait);
};
};
スロットル
スロットルは、特定の時間間隔で一度だけ関数を実行する技術です。例えば、スクロールイベントやリサイズイベントのように頻繁に発生するイベントに対して使用されます。
以下は、スロットル関数の基本的な実装です:
const throttle = (callback, limit) => {
let lastCall = 0;
return function(...args) {
const now = Date.now();
if (now - lastCall >= limit) {
lastCall = now;
callback.apply(this, args);
}
};
};
精密スロットル
精密スロットルでは、初回実行(leading)と最終実行(trailing)を制御できます。これにより、より柔軟な動作が可能になります。
const advancedThrottle = (fn, delay, options = {}) => {
const { leading = true, trailing = true } = options;
let lastExecution = 0;
let timerId;
return function(...args) {
const now = Date.now();
const remainingTime = lastExecution + delay - now;
if (remainingTime <= 0) {
if (leading) {
lastExecution = now;
fn.apply(this, args);
}
if (trailing) {
timerId = setTimeout(() => {
lastExecution = Date.now();
fn.apply(this, args);
}, delay);
}
} else if (trailing && !timerId) {
timerId = setTimeout(() => {
lastExecution = Date.now();
fn.apply(this, args);
}, remainingTime);
}
};
};
これらのテクニックを使うことで、パフォーマンスの最適化やサーバーへの負荷軽減が期待できます。