前端開發時常常會遇到事件頻繁執行的狀況:例如網頁滾動、模糊搜尋等,大量且頻繁觸發事件會非常浪費資源、且造成網頁非常卡。
該怎麼解決呢?來看看 Debounce
& Throttle
這兩個東西。
Debounce
指的是 這個函式在某段期間內不論被觸發了多少次、都只會執行最後一次。
要怎麼定義 某個期間?我們會使用定時器 setTimeout
來完成。
以生活中坐公車的例子來看:我們規定司機在最後一位乘客上車後 5 秒後關門,如果 5 秒內又有新乘客上車,那麼重新計算 5 秒。
function debounce(fn, wait = 1000) {
let timer = null;
return function (...args) {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, wait);
};
}
上面的 wait
我們定義為 1000,所以持續在 1 秒內頻繁觸發的話,時間會持續往後延,直到最後一個事件為止。
可以在 scroll
事件中嘗試看看。
window.addEventListener("scroll", debounce(() => {
console.log(window.scrollY);
}));
Debounce
雖然好,但還有另一種情況:如果使用者長時間持續執行該事件、那這個事件就會遲遲無法執行。
所以我們使用 Throttle
來減緩事件觸發,只要計時器的時間一到、我們就執行該事件,程式碼則會記錄時間與上次做比較。
function throttle(func, time = 250) {
let last;
let timer;
return function () {
const context = this;
const args = arguments;
const now = +new Date();
if (last && now < last + timeout) {
clearTimeout(timer);
timer = setTimeout(function () {
last = now;
func.apply(context, args);
}, timeout);
} else {
last = now;
func.apply(context, args);
}
};
}
以上就是簡易的 Debounce & Throttle 使用,學習之前可以先看一下 閉包 和 this指向 的觀念,會更加理解程式碼。
另外如果要實作無限載入這種滾動效果的話,可以考慮使用 Intersection Observer
這個新的 Web API,使用上的效能會更好。