前端效能優化(1) - Debounce
JavaScript
#Notes #JavaScript #Frontend Debounce 是一種常見的效能優化方式,主要用於限制高頻事件的觸發次數,例如當你使用 Google 搜尋某個關鍵字 ,它並不會在你輸入過程不斷搜尋,而是當你停下輸入後才去做搜尋的動作。
防抖 ( Debounce )
防抖 ( Debounce ) 主要用途在先前描述已經有簡單介紹過,當然不僅僅是用在搜尋上
常見的用途還有:
- 滾動事件處理
- 拖拽事件
- 表單提交
- 自動保存
- API 請求
透過 Debounce 就能夠減少不必要的操作或請求
主要關鍵還是在控制執行頻率,同時又不影響功能正常運作的場景,比較適合用於不需要立即回應,可以稍微延遲的操作
實作
要實作 Debounce 主要方向有:
- closure
- setTimeout
- 通常接收兩個參數:要被 debounce 的原始函式和 delay 時間
範例:
function debounce(func, delay = 1000) {
let timer;
// ...args 用於接收所有參數
return function(...args) {
// 清除舊的 timer 後重新計時
clearTimeout(timer);
// delay 時間到執行 func
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
// 原始函式
function handleSearch(query) {
console.log("Searching for:", query);
}
// 使用方法
const debouncedSearch = debounce(handleSearch, 1500);
searchInput.addEventListener('input', debouncedSearch);
這邊的核心概念就是透過 clearTimeout()
,當每次觸發事件時去清除舊的 timer 後再重新計時,直到停下來沒有再觸發,它就會在新 setTimeout()
中等待到計時結束,呼叫 func()
Debounce 技術的應用場景非常多,上述的程式碼只需要根據你的需求去調整原始函式和 delay 時間就可以了~
封裝成 React Hook
這邊也可以將它封裝成 Hook 來去做應用,未來也便做 Unit Test
建立一個 /hooks
資料夾,創建 useDebounce.js
// ./useDebounce.js
import { useCallback, useRef } from 'react';
function useDebounce(func, delay = 1000) {
const timerRef = useRef(null);
return useCallback((...args) => {
if (timerRef.current) {
clearTimeout(timerRef.current);
}
timerRef.current = setTimeout(() => {
func(...args);
}, delay);
}, [func, delay]);
}
export default useDebounce;
在 Component 中直接匯入就可以使用了
import React, { useState } from 'react';
import useDebounce from './useDebounce'; // 先前封裝的 hook
function SearchComponent() {
const [searchTerm, setSearchTerm] = useState('');
// 原始函式
const handleSearch = (query) => {
console.log("Searching for:", query);
// 這裡可以根據需求做調整
};
// 使用方式
const debouncedSearch = useDebounce(handleSearch, 1500);
const handleInputChange = (event) => {
const newValue = event.target.value;
setSearchTerm(newValue);
debouncedSearch(newValue);
};
return (
<input
type="text"
value={searchTerm}
onChange={handleInputChange}
placeholder="Search..."
/>
);
}