前端性能優化之防抖與節流,大幅度降低你的事件處理性能
JavaScript代碼優化——防抖和節流
引言
正文
一、初步了解
二、防抖
(1)定義
(2)使用
三、節流
(1)定義
(2)使用
四、總結
結束語
引言
看到這個標題就懵了, 你會有以下幾個問題:什么是防抖? 什么是節流? 如何使用防抖? 如何使用節流? 什么時候需要用到防抖和節流? 為什么要用防抖和節流? 那我們就圍繞這幾個問題來講一講防抖與節流的兩個概念和簡單應用吧~ 我會在正文中給大家逐個解答問題
正文
如果你不想看具體過程,也可以直接跳到總結,不過還是希望你慢慢看下去哦,因為這對你理解這兩個操作很有幫助。
一、初步了解
首先,在正文開始之前我們來看一個例子,來了解一下應用防抖和節流的初衷。
先放代碼, 其中css代碼中,實現導航欄懸停的屬性,不明白的可以去看我的另一篇文章介紹,只需要一分鐘不到就可以明白css3新屬性position: sticky 一分鐘實現 導航欄懸停功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
效果展示
我們可以看到, scroll事件是一個頻發事件,我們只是簡單的往下滾動, 但scroll 事件卻觸發了很多很多很多次。 但是我們的目的可能只是想獲得滾動停下來以后導航欄距離文檔頂部的距離, 我們并不需要滾動停止前那過程中變化的距離, 如果一直在滾動時去獲取距離,這非常影響性能,這是我們就需要用到 防抖和節流了。
二、防抖
(1)定義
抖,聽起來就是一個頻繁觸發的動作,我們可以想象我們在跑步,每跑一步就出很多的汗,我們跑的過程中,很想拿毛巾擦一擦汗,但是一想,如果剛擦完汗,跑幾步就又出汗了,還不如不擦,我看看我等會還跑不跑,如果還跑,那我就一直不擦汗,如果我什么時候不跑了,我就開始擦一下汗。那么‘ 跑步 ’ 這個動作就可以看作我們上述代碼中的滾動事件, ’ 擦汗 ’ 就可以看成scroll 事件的處理代碼,即獲取導航欄離文檔頂部的距離。 那么防抖,就是我們滾動頁面,剛要獲取導航欄離文檔頂部的距離,但是發現等會還要繼續滾動,那么就先不獲取了,等什么時候停止滾動了,再獲取這個距離。
以上文字就是對防抖這個概念的一個形象的解釋,希望大家反復閱讀,理解了定義以后才方便理解下面的實現防抖的代碼。
(2)使用
為了解決我們正文剛開始那個例子中,頻繁獲取導航欄離文檔頂部的距離的現象,我們可以用一個setTimeout定時器來完成防抖功能
// 這里我們只修改js代碼,其他都不變
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
我們來解讀一下這段代碼:
我們在全局定義了一個用于存放定時器的變量timer, 當我們在網頁第一次滾動頁面時,觸發scroll 事件, 首先判斷 timer 是否有定時器, 因為第一次滾動觸發事件,并沒有定時器賦值給timer, 所以執行下面的代碼, 這時給 timer 賦值一個延遲為500ms的定時器,并將獲取導航欄離文檔頂部距離的代碼放在定時器中。
因為滾動事件是頻繁觸發的,緊接著又觸發了 scroll 事件。同樣的先判斷 timer 是否有定時器, 因為上一次觸發該事件給 timer 賦值了一個定時器, 但此時定時器還沒結束, 所以 timer 是有定時器的,所以執行 if 語句里的代碼, 將 timer 里的定時器給清除掉, 這時,因為在上一次定時器還沒結束時,我們就在下一次觸發事件時將上一次的定時器給清除掉了,所以上一次觸發事件沒有來得及運行獲取導航欄離文檔頂部距離的代碼。接著我們又給 timer 賦值了一個定時器。
就這樣在后面會觸發無數次的滾動事件, 代碼的運行會一直按照步驟2里的邏輯進行,這樣循環往復……
直到我們停止滾動以后, 不再觸發滾動事件了,最后一次滾動事件中給 timer賦值的 setTimeout 定時器 生效了,并打印了數據。
現在,我們來看一下,運用了防抖之后滾動頁面會有什么效果
我們可以很清楚的看到,在我們滾動的過程中,一直沒有打印數據,直到我們停止以后, 控制臺打印了導航欄離文檔頂部的距離。這就是防抖的效果,現在你有沒有對防抖有一個很深的印象了呢? 接下來我們來介紹一下第二種處理頻繁觸發事件的方法: 節流。
三、節流
(1)定義
為了介紹節流的定義,我們繼續使用跑步這一例子。想象我們在跑步,我們很熱很熱,在跑步的過程中,每隔幾秒鐘,拿毛巾擦一擦身上的汗。這里我們同樣把 ’ 跑步 ’ 看作是 滾動頁面的操作, 把 ’ 擦汗 ’ 看作是獲取導航欄離文檔頂部的距離的操作。那么,節流就是, 我們滾動頁面,獲取了一下導航欄離文檔頂部的距離, 此時我們一直在滾動頁面, 只不過我們剛獲取過距離了,就先不獲取了, 等距離上一次獲取幾秒后,我們再獲取一次吧。
也請大家仔細體會節流的含義,方便理解下面的代碼
(2)使用
節流的方法,有兩種,一種是利用時間戳,另一種是利用定時器
利用時間戳來完成節流
代碼如下:
// 同樣的這里也是只需要修改js代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
我們來解讀一下這段代碼:
我們剛開始滾動頁面,觸發滾動事件,獲取當前時間戳, 因為是第一次觸發該事件,last = 0 ,所以 if 語句成立,獲取一次導航欄離文檔頂部的距離,并給 last 賦值一個現在的時間戳。
因滾動事件頻繁觸發, 再一次觸發了滾動事件,獲取一下現在的時間戳,判斷一下,現在的時間戳減去上一次操作結束時的時間戳,發現時間相差小于1秒,所以不獲取導航欄離文檔頂部的距離,同時也不用給 last 重新賦值一個此時的時間戳
就這樣一直頻繁觸發滾動事件,按照步驟2循環往復……
直到距離上次操作超過1秒, now - last 大于1秒后,才會再一次獲取導航欄離文檔頂部的距離,并又一次給 last 賦值一個操作結束時的時間戳。
現在,我們來看一下,利用時間戳節流之后滾動頁面會有什么效果
可以很明顯的看到,利用時間戳節流以后,獲取數據操作沒有像初始的那樣頻繁觸發了,而是只要你在滾動,每隔一定時間進行一次觸發,這個時間你是可以自己隨意定義的。
利用定時器節流
代碼如下:
// 這里也只需要修改js 代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
我們來解讀一下這段代碼:
首先剛開始進行滾動, status為 false,表示沒有定時器在執行,所以給創建一個定時器并賦值給 timer
此時再一次觸發滾動事件時,if 判斷 status為 true , 表示上一次的定時器還在執行呢,所以就不做任何操作
就這樣一直觸發滾動事件,按照步驟2往復循環……
直到剛開始的定時器執行完畢以后,給 status賦值一個 false, 這時再觸發滾動事件時, if 判斷 status 為 false, 表示上一次的定時器執行完成了,于是才創建了新一輪的定時器,并賦值給 timer
從步驟2~步驟4 往復循環……
現在,我們來看一下,利用定時器節流之后滾動頁面會有什么效果
我們能很清楚的看到, 利用定時器節流的效果跟利用時間戳節流的效果差不多,如果非要說差別的話,就是利用時間戳節流,第一次滾動會立馬獲取一次數據,而利用定時器節流, 第一次獲取數據會延遲一定時間。
四、總結
簡單做個總結吧,防抖和節流的區別:
防抖是從頻繁觸發執行變為最后一次才執行
節流是從頻繁觸發執行變為每隔一段時間執行一次
結束語
相信你看完這篇文章,對防抖和節流有了很深的印象了吧, 其實在你的項目中,這兩個操作很常用, 你也可以去找找以前做過的項目,看看哪里可以用到這兩個操作的, 畢竟剛學完,還是需要練練手。關注我不迷路,以后每天給大家分享一篇關于前端面試頻繁被問到的知識點~
web前端
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。