JavaScript 中的函數節流與防抖
一、是什麼
本質上是優化高頻率執行代碼的一種手段
如:瀏覽器的 resize
、scroll
、keypress
、mousemove
等事件在觸發時,會不斷地調用綁定在事件上的回調函數,極大地浪費資源,降低前端性能
爲了優化體驗,需要對這類事件進行調用次數的限制,對此我們就可以採用throttle
(節流)和debounce
(防抖)的方式來減少調用頻率
定義
-
節流: n 秒內只運行一次,若在 n 秒內重複觸發,只有一次執行
-
防抖: n 秒後在執行該事件,若在 n 秒內被重複觸發,則重新計時
一個經典的比喻:
想象每天上班大廈底下的電梯。把電梯完成一次運送,類比爲一次函數的執行和響應
假設電梯有兩種運行策略 debounce
和 throttle
,超時設定爲 15 秒,不考慮容量限制
電梯第一個人進來後,15 秒後準時運送一次,這是節流
電梯第一個人進來後,等待 15 秒。如果過程中又有人進來,15 秒等待重新計時,直到 15 秒後開始運送,這是防抖
代碼實現
節流
完成節流可以使用時間戳與定時器的寫法
使用時間戳寫法,事件會立即執行,停止觸發後沒有辦法再次執行
使用定時器寫法,delay
毫秒後第一次執行,第二次事件停止觸發後依然會再一次執行
可以將時間戳寫法的特性與定時器寫法的特性相結合,實現一個更加精確的節流。實現如下
function throttled(fn, delay) {
let timer = null
let starttime = Date.now()
return function () {
let curTime = Date.now() // 當前時間
let remaining = delay - (curTime - starttime) // 從上一次到現在,還剩下多少多餘時間
let context = this
let args = arguments
clearTimeout(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; // 保存this指向
let args = arguments; // 拿到event對象
clearTimeout(timeout)
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
防抖如果需要立即執行,可加入第三個參數用於判斷,實現如下:
function debounce(func, wait, immediate) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout); // timeout 不爲null
if (immediate) {
let callNow = !timeout; // 第一次會立即執行,以後只有事件執行後纔會再次觸發
timeout = setTimeout(function () {
timeout = null;
}, wait)
if (callNow) {
func.apply(context, args)
}
}
else {
timeout = setTimeout(function () {
func.apply(context, args)
}, wait);
}
}
}
二、區別
相同點:
-
都可以通過使用
setTimeout
實現 -
目的都是,降低迴調執行頻率。節省計算資源
不同點:
-
函數防抖,在一段連續操作結束後,處理回調,利用
clearTimeout
和setTimeout
實現。函數節流,在一段連續操作中,每一段時間只執行一次,頻率較高的事件中使用來提高性能 -
函數防抖關注一定時間連續觸發的事件,只在最後執行一次,而函數節流一段時間內只執行一次
例如,都設置時間頻率爲 500ms,在 2 秒時間內,頻繁觸發函數,節流,每隔 500ms 就執行一次。防抖,則不管調動多少次方法,在 2s 後,只會執行一次
如下圖所示:
三、應用場景
防抖在連續的事件,只需觸發一次回調的場景有:
-
搜索框搜索輸入。只需用戶最後一次輸入完,再發送請求
-
手機號、郵箱驗證輸入檢測
-
窗口大小
resize
。只需窗口調整完成後,計算窗口大小。防止重複渲染。
節流在間隔一段時間執行一次回調的場景有:
-
滾動加載,加載更多或滾到底部監聽
-
搜索框,搜索聯想功能
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/s5buGAZVTAqjD9pQC_UgPw