防抖和節流,本質上是優化高頻率執行代碼的一種手段,比如:resize、scroll、keypress、mousemove這些事件在觸發的時候,會不斷調用綁定在事件上的回調函數,這樣極大浪費資源,降低前端性能。
為了優化體驗,需要對這類事件進行調用次數的限制,所以我們采取了防抖和節流的手段來減少調用頻率。
節流:在n秒內重復發生的事件,只有一次是生效的
防抖:在n秒后再執行該事件。
節流
完成節流可以使用時間戳與定時器的寫法,使用時間戳的寫法,事件會立即執行,停止觸發后沒有辦法再次執行:
function throttled1(fn, delay = 500) {let oldtime = Date.now()return function (...args) {let newtime = Date.now()if (newtime - oldtime >= delay) {fn.apply(null, args)oldtime = Date.now()}}
}
使用定時器的寫法,delay毫秒后第一次執行:
function throttled2(fn, delay = 500) {let timer = nullreturn function (...args) {if (!timer) {timer = setTimeout(() => {fn.apply(this, args)timer = null}, delay);}}
}
兩種寫法的結合后:
function throttled(fn, delay) {let timer = nulllet starttime = Date.now()return function () {let curTime = Date.now() // let remaining = delay - (curTime - starttime) // let context = thislet args = argumentsclearTimeout(timer)if (remaining <= 0) {fn.apply(context, args)starttime = Date.now()} else {timer = setTimeout(fn, remaining);}}
}
防抖
簡單的封裝:
function debounce(func, wait) {let timeout;return function () {let context = this; // thislet args = arguments; // eventclearTimeout(timeout)timeout = setTimeout(function () {func.apply(context, args)}, wait);}
}
防抖和節流的相同點:
- 都可以使用setTimeout實現
- 目的都是降低回調函數的執行頻率,節省計算資源
不同的是:
- 函數防抖,在連續操作結束后,處理回調,利用clearTimeout和setTimeout實現;函數節流是在一段時間只執行一次,
- 防抖關注的是一段時間內頻繁觸發的事件,只在最后執行一次;節流值關注的事一段時間內執行一次。
應用場景
防抖的使用場景有:
- 搜索框輸入,只需要用戶最后一次輸入完,再做處理
- 手機號、郵箱驗證輸入檢測
- 窗口大小resize,只需窗口調整完成后,計算窗口的大小,防止重復渲染
節流的應用場景有:
- 滾動加載,加載更多或者滾動到底部監聽
- 搜索框,搜索關聯功能