js的防抖和節流

2022-04-28 16:42:09 字數 2969 閱讀 3873

防抖和節流嚴格算起來應該屬於效能優化的知識,但實際上遇到的頻率相當高,處理不當或者放任不管就容易引起瀏覽器卡死。所以還是很有必要早點掌握的。

節流概念(throttle)

按照設定的時間固定執行一次函式,比如200ms一次。注意:固定就是你在mousemove過程中,執行這個節流函式,它一定是200ms(你設定的定時器延遲時間)內執行一次。沒到200ms,一定會返回,沒有執行**函式的。
主要應用場景有:scroll、touchmove

防抖概念(debounce)

抖動停止後的時間超過設定的時間時執行一次函式。注意:這裡的抖動停止表示你停止了觸發這個函式,從這個時間點開始計算,當間隔時間等於你設定時間,才會執行裡面的**函式。如果你一直在觸發這個函式並且兩次觸發間隔小於設定時間,則一定不會到**函式那一步。
主要應用場景有:input驗證、搜尋聯想、resize

節流實現

思路: 第一次先設定乙個變數true,第二次執行這個函式時,會判斷變數是否true,是則返回。當第一次的定時器執行完函式最後會設定變數為flase。那麼下次判斷變數時則為flase,函式會依次執行

先說乙個常見的功能,很多**會提供這麼乙個按鈕:用於返回頂部。

這個按鈕只會在滾動到距離頂部一定位置之後才出現,那麼我們現在抽象出這個功能需求--監聽瀏覽器滾動事件,返回當前滾條與頂部的距離

這個需求很簡單,直接寫:

function showtop  () 

window.onscroll = showtop

但是!在執行的時候會發現存在乙個問題:這個函式的預設執行頻率,太!高!了!。高到什麼程度呢?以chrome為例,我們可以點選選中乙個頁面的滾動條,然後點選一次鍵盤的【向下方向鍵】,會發現函式執行了8-9次

然而實際上我們並不需要如此高頻的反饋,畢竟瀏覽器的效能是有限的,不應該浪費在這裡,所以接著討論如何優化這種場景。

基於上述場景,首先提出第一種思路:在第一次觸發事件時,不立即執行函式,而是給出乙個期限值比如200ms,然後:

效果:如果短時間內大量觸發同一事件,只會執行一次函式。

實現:既然前面都提到了計時,那實現的關鍵就在於settimeout這個函式,由於還需要乙個變數來儲存計時,考慮維護全域性純淨,可以借助閉包來實現:

/*

* fn [function] 需要防抖的函式

* delay [number] 毫秒,防抖期限值

*/function

debounce(fn,delay)

else}}

當然 上述**是為了貼合思路,方便理解(這麼貼心不給個贊咩?),寫完會發現其實time = settimeout(fn,delay)是一定會執行的,所以可以稍微簡化下:

/*

****************************簡化後的分割線 *****************************

*/function

debounce(fn,delay)

timer = settimeout(fn,delay) //

簡化寫法}}

//然後是舊**

function

showtop ()

window.onscroll = debounce(showtop,1000) //

為了方便觀察效果我們取個大點的間斷值,實際使用根據需要來配置

此時會發現,必須在停止滾動1秒以後,才會列印出滾動條位置。

到這裡,已經把防抖實現了,現在給出定義:

繼續思考,使用上面的防抖方案來處理問題的結果是:

但是如果產品同學的期望處理方案是:即使使用者不斷拖動滾動條,也能在某個時間間隔之後給出反饋呢?(此處暫且不論哪種方案更合適,既然產品爸爸說話了我們就先考慮怎麼實現

其實很簡單:我們可以設計一種類似控制閥門一樣定期開放的函式,也就是讓函式執行一次後,在某個時間段內暫時失效,過了這段時間後再重新啟用(類似於技能冷卻時間)。

效果:如果短時間內大量觸發同一事件,那麼在函式執行一次之後,該函式在指定的時間期限內不再工作,直至過了這段時間才重新生效。

實現這裡借助settimeout來做乙個簡單的實現,加上乙個狀態位valid來表示當前函式是否處於工作狀態:

function

throttle(fn,delay)

//工作時間,執行函式並且在間隔期內把狀態位設為無效

valid = false

settimeout(() =>, delay)

}}/*

請注意,節流函式並不止上面這種實現方案,

例如可以完全不借助settimeout,可以把狀態位換成時間戳,然後利用時間戳差值是否大於指定間隔時間來做判定。

也可以直接將settimeout的返回的標記當做判斷條件-判斷當前定時器是否存在,如果存在表示還在冷卻,並且在執行fn之後消除定時器表示啟用,原理都一樣

*///

以下照舊

function

showtop ()

window.onscroll = throttle(showtop,1000)

執行以上**的結果是:

講完了這兩個技巧,下面介紹一下平時開發中常遇到的場景:

頁面resize事件,常見於需要做頁面適配的時候。需要根據最終呈現的頁面情況進行dom渲染(這種情形一般是使用防抖,因為只需要判斷最後一次的變化情況)

部落格參考:

js防抖和節流

在進行視窗的resize scroll,輸入框內容校驗等操作時,如果事件處理函式呼叫的頻率無限制,會加重瀏覽器的負擔,導致使用者體驗非常糟糕。此時我們可以採用debounce 防抖 和throttle 節流 的方式來減少呼叫頻率,同時又不影響實際效果。函式防抖 函式防抖 debounce 當持續觸發...

js 防抖和節流

突然被人問到節流和防抖的區別,一臉大寫的懵逼,一直以為他倆是乙個東西。那趕緊學習一下吧。定義 多次觸發事件後,事件處理函式只執行一次,並且是在觸發操作結束時執行。原理 對事件處理函式做延時執行,如果在設定的時間內再次觸發事件函式,清除定時器 cleartimeout 重新計時。適用場景 乙個輸入框連...

js 防抖和節流

很多 都會提供乙個按鈕 用於返回頂部。這個按鈕只會在滾動到距離頂部一定位置的時候才出現 監聽滾動事件,返回當前到頂部的距離 function showtop window.onscroll showtop 但是執行的時候存在乙個問題 函式預設執行頻率太高,按一次鍵盤的下方向鍵,函式就執行了9次!實際...