「JS篇」這篇文章助你理解函數防抖與函數節流
- 2019 年 10 月 5 日
- 筆記
關鍵詞 | 面試考點
防抖(debounce)
函數防抖(debounce):當持續觸發事件時,在設置的周期內沒有再觸發事件,事件處理函數才會執行一次,如果設定的周期沒有結束,又一次觸發了事件,就重新開始延時。
為了有個直觀的對比,我們先看下沒有使用debounce技術的click事件:

我們看到,當用戶頻繁點擊button按鈕時,控制台會頻繁的輸出結果,這種頻繁調用事件處理程式,會加重瀏覽器的負擔,導致用戶體驗非常糟糕。
為了解決上述問題,我們在編碼中可以使用debounce防抖技術。
防抖原理:是維護一個計時器,在規定的delay時間後觸發函數,但是在delay時間內再次觸發的話,就會取消之前的計時器而重新設置。這樣一來,只有最後一次操作能被觸發。
function debounce(fn, delay) { var timer = null; return function() { // 清除已存在的定時器 timer && clearTimeout(timer) timer = setTimeout(function() { fn.apply(this) }, delay) } } let $btn = document.getElementById('btn'); var fn = function() { console.log ('防抖旨在時間段內只觸發最後一次執行' + new Date(Date.now())); } $btn.onclick = debounce(fn, 1000);
如下圖,持續觸發click事件時,並不會每次觸發都會執行事件處理函數,當在設置的周期1000 ms內沒有再觸發click事件時,才會延時觸發click事件。

節流(throttle)
函數節流(throttle):函數執行一次後,只有在大於設置的執行周期後才會執行第二次。持續觸發事件時,保證一定時間段內只調用一次事件處理函數。
throttle翻譯為節流閥,我們可以想像成我們水龍頭放水,閥門一打開,水嘩嘩的往下流,秉著勤儉節約的優良傳統美德,我們要把水龍頭關小點,最好是如我們心意按照一定規律在某個時間間隔內一滴一滴的往下滴。
同樣我們先看一個沒有使用throttle技術的scroll事件,如下圖:

這種頻繁的scroll操作都會給瀏覽器帶來沉重的負擔,接下來我們看下如何使用throttle技術。
節流原理:是記錄上次執行的時間戳lastTime,每次觸發事件時記錄當前執行的時間戳nowTime,然後判斷nowTime與lastTime的差值是否大於設定的周期delay,如果大於,則執行回調,並更新上次執行的時間戳,從而循環。持續觸發事件時,保證一定時間段內觸發事件處理函數的頻率。
function throttle(fn, delay) { // 記錄上次觸發的時間戳 var lastTime = 0; return function() { // 記錄當前觸發的時間戳 var nowTime = Date.now(); // 如果當前觸發與上次觸發的時間差值 大於 設置的周期則允許執行 if (nowTime - lastTime > delay) { fn.call(this); // 更新時間戳 lastTime = nowTime; } } } document.onscroll = function () { console.log ('節流旨在時間段內控制觸發的頻率'+new Date(Date.now())) }
如下圖,持續觸發scroll事件時,並不立即執行處理函數,噹噹前觸發與上次觸發的時間差值大於設置的周期時才會執行。

應用場景
上面介紹了防抖(debounce) 和 節流(throttle) 的原理和實現方式。
下面簡單列出兩者的應用場景都有哪些:
防抖(debounce)應用場景:
- 每個調整大小/滾動都會觸發統計事件。
- 驗證文本輸入(在連續文本輸入後,發送
Ajax請求進行驗證)。 - 監視滾動
scroll事件(在添加去抖動後滾動,只有在用戶停止滾動後才會確定它是否已到達頁面底部)。
節流(throttle)應用場景:
- 實現DOM元素的拖放功能
mousemove。 - 搜索關聯
keyup。 - 計算滑鼠移動距離
mousemove。 - 畫布模擬草圖功能
mousemove。 - 射擊遊戲中的
mousedown/keydown事件(每單位時間只能發射一顆子彈)。 - 監視滾動
scroll事件(添加節流後,只要滾動頁面,就會每隔一段時間才會計算)。
最後,節流(throttle)旨在時間段內控制觸發的頻率;防抖(debounce)旨在時間段內只觸發最後一次。
