防抖(debounce)和節流(throttle)是什么,如何實現它們,它們之間又有什么區別呢?
在前端開發中會遇到一些頻繁的事件觸發,比如:
window
的resize
、scroll
mousedown
、mousemove
keyup
、keydown
如何解決:防抖、節流
防抖
動作綁定事件,動作發生后一定時間后觸發事件,在這段時間內,如果該動作又發生,則重新等待一定時間再觸發事件。
具體方法是:在上一次事件觸發之后的 time
時間內如果事件沒有再次觸發,那么就在 time
時間后觸發,否則將觸發的時間作為新的起始點
通俗理解就是,將密集的時間觸發事件看作一個時間整體,整個整體只觸發一次事件,密集的界定就是相鄰事件觸發時間小於 time
,則以這個整體的最后一次事件觸發為起始點
可以用數軸來理解,比如有 [2, 5]
和 [8, 11]
兩個區間可以看作密集事件發生處,那么整個 [2, 5]
時間最終都只觸發一次事件,5 是這次事件結束時,那么等待 time = 3
才再次觸發下一次事件
具體代碼:
function debounce(func, time) {
let timer = null;
return function () {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, arguments);
}, time);
};
}
這里有一個疑惑,為什么要使用閉包?
原因是 timer
變量是在 debounce
函數內部初始化的時候聲明的,但是之后每一次觸發返回的箭頭函數的時候都需要讀取 timer
變量,所以要使用閉包
還有一個疑惑,為什么要使用
func.apply(this, arguments)
而不直接使用func()
?
原因是每次調用箭頭函數的時候為了確保上下文環境為當前的 this
,就需要使用 apply
語法
節流
動作綁定事件,動作發生后一段時間后觸發事件,在這段時間內,如果動作又發生,則無視該動作,直到事件執行完后,才能重新觸發。
節流和防抖大致相同,不同點在於:
- 防抖是“隨機應變”,以密集的事件觸發處的末尾為下一次事件觸發的計時開始處
- 節流是“鐵打不動”,始終以第一次事件觸發為起始點,忽略
time
時間內的所有事件,第一次事件發生time
事件之后觸發第二次事件
在數軸上理解的相同點和區別為:
在 [2, 5]
時間內觸發的所有事件都濃縮為一次事件,區別是:防抖將此次事件的發生事件定在最后一次事件觸發的時間,節流將時間定在第一次事件觸發的時間
節流的代碼:
function throtte(func, time) {
let activeTime = 0;
return function () {
const current = Date.now();
if (current - activeTime > time) {
func.apply(this, arguments);
activeTime = Date.now();
}
};
}
從代碼的區別也可以看出:
防抖實際上是在事件密集觸發區不斷更新定時器,而節流只需要不斷讀取當前時間並且判斷是否滿足要求即可