Skip to main content

debounce(防抖) vs. throttle(節流)

什麼是 Debounce 和 Throttle?

  • Debounce(去抖動):確保某個函數在連續觸發事件後,只有在「最後一次觸發後等待一段時間」才會執行。簡單來說,它會把多次快速觸發合併成一次執行,適合用在「只需要最後結果」的場景。

    image.png

    Photo Credit: David Corbacho

  • Throttle(節流):限制某個函數在一段時間內最多執行一次。即使事件被高頻觸發,函數也只會按照設定的間隔時間執行,適合用在「需要固定頻率執行」的場景。

    image 1.png

    Photo Credit: David Corbacho

使用場景

  • Debounce

    • 搜尋框輸入:當使用者快速輸入時,只有停止輸入一段時間後才發送 API 請求。

    • 表單驗證:避免使用者快速輸入時頻繁觸發驗證邏輯。

  • Throttle

    • 滾動事件:確保滾動時的處理函數(如檢查元素是否進入可視區域)以固定間隔執行。

    • 滑鼠移動:限制滑鼠移動時的處理頻率,避免過多計算。

Debounce vs. Throttle 的核心差異

特性DebounceThrottle
執行時機事件停止觸發後,等待一段時間才執行固定時間間隔內最多執行一次
觸發頻率只有在最後一次觸發後執行一次按照固定間隔持續執行
適用場景搜尋框、表單輸入滾動事件、滑鼠移動、按鈕連點

程式碼實作:Debounce

以下是使用 JavaScript 實作 Debounce 的完整程式碼,包含 HTML 和事件綁定範例:

// Debounce 函數實作
function debounce(func, wait) {
let timeout; // 用來儲存計時器
return function (...args) {
// 清除之前的計時器
clearTimeout(timeout);
// 設定新的計時器
timeout = setTimeout(() => {
func.apply(this, args); // 執行函數
}, wait);
};
}
// 模擬搜尋函數
function search(query) {
document.getElementById('result').textContent = query;
console.log('搜尋:', query);
}
// 將搜尋函數包裝成 Debounce 版本,等待 500ms
const debouncedSearch = debounce(search, 500);
// 綁定輸入事件
const input = document.getElementById('searchInput');
input.addEventListener('input', (event) => {
debouncedSearch(event.target.value);
});

// Debounce 函數實作
function debounce(func, wait) {
let timeout; // 用來儲存計時器
return function (...args) {
// 清除之前的計時器
clearTimeout(timeout);
// 設定新的計時器
timeout = setTimeout(() => {
func.apply(this, args); // 執行函數
}, wait);
};
}
// 模擬搜尋函數
function search(query) {
document.getElementById('result').textContent = query;
console.log('搜尋:', query);
}
// 將搜尋函數包裝成 Debounce 版本,等待 500ms
const debouncedSearch = debounce(search, 500);
// 綁定輸入事件
const input = document.getElementById('searchInput');
input.addEventListener('input', (event) => {
debouncedSearch(event.target.value);
});

說明

  1. HTML:包含一個輸入框和一個顯示搜尋結果的區域。

  2. Debounce 函數

    • 接受兩個參數:func(要執行的函數)和 wait(等待時間,單位為毫秒)。

    • 使用 setTimeout 設定計時器,每次事件觸發時清除上一次的計時器,重新設定新的計時器。

    • 只有在最後一次觸發後等待 wait 毫秒後,函數才會執行。

  3. 使用方式:當使用者在輸入框快速輸入時,只有停止輸入 500ms 後,search 函數才會執行,更新畫面上的搜尋結果。

操作步驟

  1. 複製以上程式碼到一個 .html 檔案。

  2. 在瀏覽器中開啟,快速輸入文字,觀察 console.log 和畫面更新只在停止輸入 500ms 後發生。


程式碼實作:Throttle

以下是使用 JavaScript 實作 Throttle 的完整程式碼,包含 HTML 和事件綁定範例:

// Throttle 函數實作
function throttle(func, wait) {
let lastCall = 0; // 記錄上次執行時間

return function (...args) {
const now = Date.now();
// 如果距離上次執行超過 wait 時間,則執行函數
if (now - lastCall >= wait) {
func.apply(this, args);
lastCall = now; // 更新上次執行時間
}
};
}
// 模擬滾動處理函數
let count = 0;
function handleScroll() {
count++;
document.getElementById('scrollCount').textContent = count;
console.log('滾動處理:', count);
}
// 將滾動處理函數包裝成 Throttle 版本,每 1000ms 執行一次
const throttledScroll = throttle(handleScroll, 1000);
// 綁定滾動事件
window.addEventListener('scroll', throttledScroll);
// Throttle 函數實作
function throttle(func, wait) {
let lastCall = 0; // 記錄上次執行時間

return function (...args) {
const now = Date.now();
// 如果距離上次執行超過 wait 時間,則執行函數
if (now - lastCall >= wait) {
func.apply(this, args);
lastCall = now; // 更新上次執行時間
}
};
}
// 模擬滾動處理函數
let count = 0;
function handleScroll() {
count++;
document.getElementById('scrollCount').textContent = count;
console.log('滾動處理:', count);
}
// 將滾動處理函數包裝成 Throttle 版本,每 1000ms 執行一次
const throttledScroll = throttle(handleScroll, 1000);
// 綁定滾動事件
window.addEventListener('scroll', throttledScroll);

說明

  1. HTML:包含一個長頁面(方便滾動)和一個顯示滾動次數的區域。

  2. Throttle 函數

    • 接受兩個參數:func(要執行的函數)和 wait(間隔時間,單位為毫秒)。

    • 使用 Date.now() 記錄當前時間,檢查距離上次執行是否超過 wait 時間。

    • 如果超過 wait 時間,則執行函數並更新上次執行時間。

  3. 使用方式:當使用者滾動頁面時,handleScroll 函數每 1000ms 最多執行一次,更新滾動次數。

操作步驟

  1. 複製以上程式碼到一個 .html 檔案。

  2. 在瀏覽器中開啟,快速滾動頁面,觀察 console.log 和畫面更新每秒最多發生一次。


Debounce vs. Throttle 的視覺化比較

假設事件每 100ms 觸發一次,wait 時間設為 500ms:

  • Debounce:事件連續觸發,只有最後一次觸發後等待 500ms 才執行一次。

    事件:|----|----|----|----|----| 

    執行: |----|
  • Throttle:事件連續觸發,每 500ms 執行一次。

    事件:|----|----|----|----|----| 

    執行:|----| |----|

如何選擇 Debounce 或 Throttle?

  • 如果你希望「減少不必要的執行次數」,並只關心「最後結果」,選擇 Debounce(如搜尋框輸入)。

  • 如果你希望「以固定頻率執行」,並確保事件期間有持續回應,選擇 Throttle(如滾動或滑鼠移動)。