摘要:運用防抖和節流可以有效降低代碼的執行頻率,從而解決高頻率事件的頁面卡頓問題。在階段布局,最終確定顯示的位置和大小。在函數中,首先定義了一個空的定時器變量,用來計算時間間隔。還有一點要注意,在中一定要清楚定時器,不然會影響的條件判斷。
啥是節流?
節流是保證在一段時間內,代碼只執行了一次。這個一段時間內指的是不管用戶操作了幾次,最終僅執行一次。比如說一個按鈕,用戶狂點按鈕,但是如果用節流技術的話,不管用戶點擊了幾次,最終某個時間段內只執行了一次代碼。這個時間段是可以自行設置,比如說每一秒執行一次。
啥是防抖?
防抖其實和節流有些類似,畢竟它們的最終目的都是如出一轍。防抖是在一段時間結束之后,才觸發一次事件。如果一段時間內未結束再次觸發了事件,那么就會重新計算這段時間。同樣的例子,還是用戶狂點按鈕。但是僅在用戶停止點擊按鈕后的一段時間之后才會執行一次。如果用戶暫停點擊按鈕的時間不到一段時間內又再次點擊按鈕,那么就會重新計算時間。這個時間同樣可以自行設置。
為啥要防抖或節流呢?
為了優化高頻率事件,比如說onscroll滾動 oninput搜索框聯想 resize窗口大小變化 onkeydown onkeyup...等等。這些高頻率事件很有可能導致頁面卡頓,影響用戶體驗。運用防抖和節流可以有效降低代碼的執行頻率,從而解決高頻率事件的頁面卡頓問題。或許還有疑問,為啥高頻事件就會導致頁面卡頓呢?
這就要從頁面的展示過程說起了。
頁面的展示過程
展示過程大致為以下順序:
Javascript -> Style -> Layout -> Paint -> Composite
首先,Javascript階段會往頁面中添加一些DOM或動畫,然后到Style階段確定每個DOM應該用什么樣式規則。在Layout階段布局,最終確定DOM顯示的位置和大小。在Paint階段進行DOM的繪制,它是在不同層上進行繪制。注意,樣式變化是重繪,布局和位置變化是重排。重排一定導致重繪,重繪不一定導致重排。最后一個階段Composite進行渲染層合并。(所以做一些動畫效果盡量用CSS3的transform等屬性,因為該屬性是脫離文檔流,不用合并渲染層的。)由此可見,如果觸發了很多高頻率的事件,就會導致頁面不停的確定位置和大小 ,不停的重排重繪并且合并渲染層。所以導致頁面卡頓也可以解釋了。
接下來會用例子來一步步實現節流和防抖的原理。
節流
首先 比如頁面上有個按鈕,用戶可以點擊該按鈕。該按鈕上綁定了一個點擊事件,用戶可以瘋狂點擊觸發該事件,肯定結果就是瘋狂觸發該事件。目標是讓該按鈕不管用戶點擊的多快,最終該事件每秒僅執行一次。
throttle 按鈕
可以看到,用戶瘋狂點擊了20次,那么該事件也理所當然的執行了20次,這顯然不是我們想要的。
基礎版:
按鈕
為了盡可能的減少篇幅,把一些無用的代碼都刪除了。
定義一個throttle方法,該方法傳入了兩個參數,一個是要執行的事件,另一個是間隔時間。該throttle方法是一個閉包的寫法,并且返回了一個函數。首先定義了上次的時間戳pre,pre默認第一次為0。然后獲取到當前時間,用當前時間減去上次的時間戳也就是pre,如果這個差值大于了傳遞的時間間隔wait,也就表明可以執行下一次的函數了。所以執行方法并且傳遞this和參數。并把當前時間賦給pre,以便做下一次節流的判斷。 看下效果:
可以看到,雖然瘋狂點擊按鈕,但是事件卻沒有瘋狂觸發,保持了每一秒執行一次的速度。也就達成了我們的目標。
但是還有一個問題就是,我最后點擊按鈕的那次也應該延遲觸發最后一次的事件,但是結果并沒有。需要補上最后一次沒有觸發事件的問題,接下來優化它。
進階版:
按鈕
很明顯看到,進階版多傳了一個參數對象,trailing:true。該參數用來表示是否執行最后一次觸發的方法。
在函數中,首先定義了一個空的定時器變量timeout,用來計算時間間隔。其次多了一個else if的條件判斷,判斷如果時間間隔小于wait,就表示該方法要保留起來延遲去執行。所以生成了一個定時器,延遲執行later函數,later函數就是執行該func函數。此處注意一點,這個延遲時間的問題。延遲時間不能是wait,必須是wait減去當前時間和上次時間的時間獎額。剩下的才是剩余時間延遲。還有一點要注意,在if中一定要清楚定時器,不然會影響else if的條件判斷。經過測試,確實能在點擊的最后一次后,延遲不到一秒觸發了該事件。
剩下最后一個優化點,其實第一次點擊按鈕,也應該延遲觸發事件。目前的版本是點擊按鈕的第一次就直接觸發該事件。優化它:
最終版:
按鈕
可以看到,傳遞一個新的參數對象leading為false。用來表示第一次也延遲執行。那么問題來了,怎樣才能第一次延遲執行呢?實現其實很簡單,進階版已經實現了else if延遲執行,現只需讓第一次不走if,走else if就可實現第一次的延遲執行。總共改動僅兩處,第一處:判斷用戶是否傳遞了參數leading為false。如果傳遞了leading為false,則把當前時間now賦給上次時間pre。為何這樣做呢? 目的就是為了第一步的時候也走else if。這么看。pre=now 那么if判斷條件就相當與now-now。now-now=0,當然不滿足if條件,即第一次走了else if。這還不算完,在else if中要校正pre時間。如果option.leading為false,那么pre就初始為0。pre為0的就會走if。只有走了if才會清空定時器,不然的話只會執行一次便不會繼續往下執行。因為if和else if的判斷條件都不滿足。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/117494.html
摘要:運用防抖和節流可以有效降低代碼的執行頻率,從而解決高頻率事件的頁面卡頓問題。在階段布局,最終確定顯示的位置和大小。在函數中,首先定義了一個空的定時器變量,用來計算時間間隔。還有一點要注意,在中一定要清楚定時器,不然會影響的條件判斷。 啥是節流? 節流是保證在一段時間內,代碼只執行了一次。這個一段時間內指的是不管用戶操作了幾次,最終僅執行一次。比如說一個按鈕,用戶狂點按鈕,但是如果用節流...
摘要:函數防抖和節流,都是控制事件觸發頻率的方法。封裝一個函數,讓持續觸發的事件監聽是我們封裝的這個函數,將目標函數作為回調傳進去,等待一段時間過后執行目標函數第二點實現了,再看第一點持續觸發不執行。 曾經面試時候被問到過這個,年少的我一臉無知。。。 后來工作中遇到了一個場景:輸入名稱的同時去服務器校驗名稱是否重復,但發現之前的代碼竟然都沒做限制,輸入一次發一次請求。簡直忍不了,就在項目的u...
摘要:文章來源詳談防抖和節流輕松理解函數節流和函數防抖函數防抖和節流好啦,今天的小菊花課堂之的防抖與節流的內容就告一段落啦,感各位能耐心看到這里。 前言 陸游有一首《冬夜讀書示子聿》——古人學問無遺力,少壯工夫老始成。紙上得來終覺淺,絕知此事要躬行。,其中的意思想必大家都能明白,在學習或工作中,不斷的印證著這首詩的內涵。所以,又有了此篇小菊花文章。 詳解 在前端開發中,我們經常會碰到一些會持...
摘要:文章來源詳談防抖和節流輕松理解函數節流和函數防抖函數防抖和節流好啦,今天的小菊花課堂之的防抖與節流的內容就告一段落啦,感各位能耐心看到這里。 前言 陸游有一首《冬夜讀書示子聿》——古人學問無遺力,少壯工夫老始成。紙上得來終覺淺,絕知此事要躬行。,其中的意思想必大家都能明白,在學習或工作中,不斷的印證著這首詩的內涵。所以,又有了此篇小菊花文章。 詳解 在前端開發中,我們經常會碰到一些會持...
閱讀 1200·2021-11-23 09:51
閱讀 1980·2021-10-08 10:05
閱讀 2339·2019-08-30 15:56
閱讀 1900·2019-08-30 15:55
閱讀 2639·2019-08-30 15:55
閱讀 2487·2019-08-30 13:53
閱讀 3497·2019-08-30 12:52
閱讀 1249·2019-08-29 10:57