Web Vitals中階
什麼是防抖 (debounce)?如何實踐防抖 (debounce) 函式?
什麼是 Debounce(防抖)?
防抖:當事件被高頻觸發時,只有在「最後一次觸發後的 N 毫秒內沒有再被觸發」,才真正執行函式。如果在等待期間事件又被觸發,就重新計時。
核心精神:只在「停下來」之後才執行。
常見應用情境
- 搜尋框輸入自動補全(使用者停止輸入後才發請求)
- 視窗 resize 後才重算版面
- 表單欄位即時驗證
- 按鈕防止連續快點(送出表單)
基本實作
function debounce(fn, delay = 300) {
let timer = null;
return function (...args) {
// 每次觸發先清掉上一次的計時器
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
timer = null;
}, delay);
};
}
使用:
const onInput = debounce((e) => {
console.log('search:', e.target.value);
}, 500);
input.addEventListener('input', onInput);
進階版:支援 leading / trailing 與 cancel
leading: 第一次觸發時立刻執行trailing: 最後一次觸發後執行(預設)cancel(): 取消尚未執行的 callback
function debounce(fn, delay = 300, { leading = false, trailing = true } = {}) {
let timer = null;
let lastArgs = null;
let lastThis = null;
function invoke() {
fn.apply(lastThis, lastArgs);
lastArgs = lastThis = null;
}
function debounced(...args) {
lastArgs = args;
lastThis = this;
const callNow = leading && !timer;
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
timer = null;
if (trailing && lastArgs) invoke();
}, delay);
if (callNow) invoke();
}
debounced.cancel = () => {
clearTimeout(timer);
timer = null;
lastArgs = lastThis = null;
};
return debounced;
}
實作細節
- 使用閉包保存
timer,讓每次呼叫 debounced 函式共享同一個計時器。 - 以
fn.apply(this, args)保留原函式的this與參數。 - React 中要用
useCallback/useRef包裝,避免每次 render 產生新的 debounced 函式。
Debounce vs Throttle
| 比較 | Debounce | Throttle |
|---|---|---|
| 策略 | 最後一次觸發後才執行 | 每隔固定時間執行一次 |
| 適用 | 搜尋、resize、輸入驗證 | scroll、mousemove、射擊遊戲 |
| 類比 | 電梯:最後一個人進來後才關門 | 水龍頭:固定流速滴水 |
✦ AI 模擬面試
輸入你的答案,AI 即時分析精準度與改進空間
登入後即可使用 AI 評分
