文章中英模式
常見的前端面試題目 - 用戶交互優化 - Throttle 與 Debounce
深入理解 JavaScript 中的 Throttle 節流與 Debounce 防抖技術,包含兩者差異、實作原理、適用場景詳解與實際範例,掌握前端效能優化與面試常考題目。
文章中英模式

懶得看文章?那就來看影片吧
什麼是 Throttle 與 Debounce?為什麼需要它們?
Throttle(節流)和 Debounce(防抖)是兩種常用的前端效能優化技術,用於控制高頻事件(如滾動、搜索、調整視窗大小)的執行頻率。
- •Throttle(節流):限制函式在一段時間內只執行一次,無論觸發多少次。像是「每隔 N 毫秒最多執行一次」。
- •Debounce(防抖):將多次連續觸發合併為一次,只在最後一次觸發後等待一段時間才執行。像是「等待 N 毫秒沒有新觸發才執行」。
這兩種技術對於優化前端效能、提升使用者體驗非常重要:
- •減少不必要的函式呼叫
- •降低 API 請求頻率
- •優化資源密集型計算
- •減少 DOM 操作頻率
Throttle(節流)實作與原理
節流的核心概念是「保證在指定時間內,函式最多只能執行一次」:
function throttle(func, delay) {
let lastCall = 0;
return function(...args) {
const now = Date.now();
if (now - lastCall >= delay) {
func.apply(this, args);
lastCall = now;
}
};
}
// 使用範例
const throttledScroll = throttle(() => {
console.log('滾動位置:', window.scrollY);
}, 300);
window.addEventListener('scroll', throttledScroll);圖解 Throttle 執行原理:
觸發事件:↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
執行函式:↓ ↓ ↓
時間軸: |--------|--------|------->
300ms 300ms 300msDebounce(防抖)實作與原理
防抖的核心概念是「等待指定時間內沒有新的呼叫再執行函式」:
function debounce(func, delay) {
let timer = null;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
// 使用範例
const searchInput = document.getElementById('search');
const debouncedSearch = debounce((e) => {
console.log('搜尋關鍵字:', e.target.value);
// fetchResults(e.target.value);
}, 500);
searchInput.addEventListener('input', debouncedSearch);圖解 Debounce 執行原理:
觸發事件:↓ ↓ ↓ ↓ ↓ ↓
重設計時:⟳ ⟳ ⟳ ⟳ ⟳ ⟳
執行函式: ✓ ✓
時間軸: |-----|-----|-----|-----|---->
等待中 等待中 執行 等待中 執行使用場景比較
Throttle 與 Debounce 適用場景比較:
| 技術 | 適用場景 | 實際應用 |
|---|---|---|
| Throttle(節流) | 滾動事件處理 | 社交媒體的無限滾動加載,每300ms檢查一次滾動位置 |
| 遊戲中的按鍵控制 | 射擊遊戲中限制玩家每秒最多發射5顆子彈 | |
| 地圖拖動/縮放 | Google地圖拖動時,每100ms才重新請求地圖數據 | |
| Canvas 繪圖 | 繪圖應用中,筆刷跟隨滑鼠以固定間隔繪製點 | |
| Debounce(防抖) | 搜尋框輸入 | Google搜尋框停止輸入500ms後才發送搜尋請求 |
| 表單驗證 | 註冊表單中,用戶輸入完郵箱後才檢查是否已被使用 | |
| 自動保存 | Google文件在用戶停止輸入2秒後自動保存內容 | |
| 窗口大小調整 | 響應式網站在用戶完成調整視窗大小後才重新排版 |
實際應用案例與效能差異
案例 1:滾動事件優化(使用 Throttle)
未優化前,滾動時可能會觸發上百次函式呼叫:
// 未優化 - 每次滾動都會執行
window.addEventListener('scroll', () => {
loadMoreContent();
});
// 優化後 - 每 200ms 最多執行一次
window.addEventListener('scroll', throttle(() => {
loadMoreContent();
}, 200));案例 2:自動保存表單(使用 Debounce)
未優化前,輸入每個字都會觸發保存:
// 未優化 - 每次輸入都會保存
editor.addEventListener('input', saveContent);
// 優化後 - 停止輸入 500ms 後才保存
editor.addEventListener('input', debounce(saveContent, 500));🔥 常見面試題目
(一)Throttle 和 Debounce 的主要區別是什麼?
解答:Throttle(節流)控制函式在一段時間內最多執行一次,無論觸發多少次,適合持續性事件如滾動。例如:在電商網站上,當使用者滾動頁面時,使用 Throttle 每 200ms 檢查一次是否需要載入更多商品,而不是每次滾動都觸發。Debounce(防抖)則是將多次連續觸發合併為一次,只在最後一次觸發後等待一段時間才執行,適合連續觸發但只需最終結果的場景如搜尋。例如:在搜尋框中,使用者快速輸入「React 教學」時,使用 Debounce 等待使用者停止輸入 500ms 後才發送 API 請求,而不是每打一個字就發送一次請求。
(二)以下程式碼的執行結果是什麼?
let count = 0;
const btn = document.getElementById('btn');
const throttledClick = throttle(() => {
console.log(`點擊次數: ${++count}`);
}, 1000);
// 假設使用者在 2 秒內快速點擊 5 次
btn.addEventListener('click', throttledClick);解答:假設使用者在 2 秒內點擊 5 次,console 會輸出:
- 第 0 秒時:「點擊次數: 1」(首次立即執行)
- 第 1 秒時:「點擊次數: 2」(間隔滿 1 秒後執行)
- 第 2 秒時:「點擊次數: 3」(間隔滿 1 秒後執行)
(三)以下 debounce 程式碼的執行結果是什麼?
let count = 0;
const searchInput = document.getElementById('search');
const debouncedSearch = debounce(() => {
console.log(`搜尋次數: ${++count}`);
}, 500);
// 假設使用者在 1 秒內快速輸入 5 個字元
searchInput.addEventListener('input', debouncedSearch);解答:假設使用者在 1 秒內快速輸入 5 個字元,console 會輸出:
- 第 1.5 秒時:「搜尋次數: 1」(最後一次輸入後 500ms 執行)
(四)實作一個簡單的搜尋框 Debounce
解答:以下是一個簡單的搜尋框 Debounce 實作:
// HTML: <input id="search" type="text" placeholder="搜尋...">
// HTML: <div id="results"></div>
function debounce(func, delay) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => func(...args), delay);
};
}
const searchInput = document.getElementById('search');
const resultsDiv = document.getElementById('results');
const handleSearch = debounce((event) => {
const query = event.target.value;
resultsDiv.textContent = `搜尋中: ${query}`;
// 實際應用中這裡會發送 API 請求
}, 300);
searchInput.addEventListener('input', handleSearch);