飯糰
ONIGIRI常駐監工
主樓2026-08-12
飯糰

Haru Li

前端工程師

發表 14 篇

·約 2 分鐘效能JavaScript

防抖與節流:同一串輸入,送出次數差多少

debouncethrottle 是那種「知道有這兩個東西,但每次都要想一下差在哪」的名詞。我做這個 demo 就是為了不用再想。

發想:把次數印出來

輸入框每打一個字,就算一次「要送出的請求」。三種策略同時處理同一串輸入,各自計數。

不用解釋定義,看數字就懂。

測試:快速連打一段字再停手

三個計數器:

  • 原始:每次輸入都送。次數會跟你的按鍵數一模一樣。
  • 防抖(debounce):打字期間一次都不送,停手之後才送一次。
  • 節流(throttle):打字期間穩定地送,但有固定的間隔上限。

打一段長一點的字最明顯:原始可能二十幾次,防抖只有 1 次,節流落在中間且跟你打字的時間長度成正比,跟按了幾個鍵無關。

理解:兩種完全不同的問題

防抖問的是「你講完了嗎」。每次有新事件就把計時器重設,只有安靜超過設定的時間才真的執行。

function debounce(fn, ms) {
  let timer;
  return (...args) => {
    clearTimeout(timer);              // ← 重點:每次都重設
    timer = setTimeout(() => fn(...args), ms);
  };
}

節流問的是「上次是多久以前」。在設定的間隔內最多執行一次,中間的事件直接丟掉。

function throttle(fn, ms) {
  let last = 0;
  return (...args) => {
    const now = Date.now();
    if (now - last < ms) return;      // ← 重點:還沒到時間就不做
    last = now;
    fn(...args);
  };
}

差別在中間那段時間有沒有反應。防抖是完全安靜,節流是穩定輸出。

講解:怎麼選

情境 該用 為什麼
搜尋建議 防抖 打到一半的字送出去沒有意義
表單即時驗證 防抖 同上,打到一半就報錯很煩
捲動位置追蹤 節流 捲動期間就需要持續更新
拖曳 / 視窗縮放 節流 過程中畫面要跟著動
送出按鈕防連點 節流 第一次要立刻生效,後續擋掉

一個判準:「過程中需不需要反應」。需要就節流,不需要就防抖。

還有一個常被忽略的細節:防抖的延遲要選得夠短,不然使用者會覺得系統遲鈍。搜尋建議常用 200–300 ms,長到 500 ms 以上就會有「怎麼還沒出來」的感覺。

(另外,捲動監聽現在多數情況可以直接用 IntersectionObserver 取代,連節流都不必——這一頁的錨點導覽就是這樣做的。)


這個 demo 可以在 效能實驗室 自己操作。

這裡的文章都寫在自家 repo 的 markdown 檔裡,發文就是新增一個檔案。

© 2026 HARU LI