9012年了,不做不懂函式防抖和函式節流的前端
概述
- 函式防抖: 任務頻繁觸發的情況下,只有任務觸發的間隔超過指定間隔的時候,任務才會執行。
- 函式節流: 指定時間間隔內只會執行一次任務,原本可能會無時無刻執行的函式。
總之都是為了節省計算資源。
函式防抖(debounce)
場景:
- 如今很多網站為了提高使用者體驗,不會再輸入框失去焦點的時候再去判斷使用者名稱是否被佔用,而是在輸入的時候就在判斷這個使用者名稱是否已被註冊。當用戶輸入第一個字元後的一段時間內如果還有字元輸入的話,那就暫時不去請求判斷使用者名稱是否被佔用。
- 使用者註冊時候的手機號碼驗證和郵箱驗證
任務頻繁觸發的情況下,只有足夠的空閒時間,才執行程式碼一次。
基本思想:通過閉包
儲存一個標記(timeout)來儲存setTimeout
返回的值,每當使用者輸入的時候把前一個setTimeout
clear 掉,然後又建立一個新的setTimeout
,這樣就能保證輸入字元後的interval
間隔內如果還有字元輸入的話,就不會執行fn
函數了。
函式防抖的要點:也是需要一個setTimeout
來輔助實現。延遲執行需要跑的程式碼。
如果方法多次觸發,則把上次記錄的延遲執行程式碼用clearTimeout
清掉,重新開始。
如果計時完畢,沒有方法進來訪問觸發,則執行程式碼。
// 函式防抖 function debounce(handlerFunc, interval = 300) { let timeout = null; return function () { clearTimeout(timeout); timeout = setTimeout(() => { handlerFunc.apply(this, arguments); }, interval); }; }
//繫結監聽 window.addEventListener('resize', () => { debounce(this.onResize, 40) }, false);
函式節流(throttle)
場景:過多的DOM相關操作可能會導致瀏覽器掛起,有時候甚至會崩潰。比如:onresize、onscroll、mousemove等。
為了避免類似問題,就可以使用定時器對該函式進行節流。
基本思想:某些程式碼不可以在沒有間斷的情況下連續重複執行,就是一定時間內函式只執行一次。
第一次呼叫函式,建立一個定時器,在指定的時間間隔之後執行程式碼 。當第二次呼叫函式時,它會清除前一次的定時器並設定另一個。如果前一個定時器尚未執行,就是將其替換為一個新的定時器,目的是隻有在執行函式的請求停止了一段時間之後才執行。
函式節流的要點:宣告一個變數(resizeTimeout)當標誌位,記錄當前程式碼是否在執行。
- 如果空閒,則可以正常觸發方法執行。
- 如果程式碼正在執行,則取消這次方法執行。
注意:只要是程式碼週期性執行的,都應該使用節流,但是並不能控制請求執行的速率。
// 函式節流 function throttle(handlerFunc, timeout = 66) { let resizeTimeout; if (!resizeTimeout) { resizeTimeout = setTimeout(() => { resizeTimeout = null; handlerFunc(); // The actualResizeHandler will execute at a rate of 15fps }, timeout); } }
//繫結監聽 window.addEventListener('resize', () => { throttle(this.onResize, 40) }, false);
總結
函式防抖和函式節流的名字起得易混淆,要找技巧理解記憶,通俗易懂的說:
函式防抖就像快遞小哥先將外賣攢著一起,只有超過規定間隔的時候才集中送一次。
函式節流就像王者榮耀中任務技能,放一次大招之後,需要CD冷卻時間過了,才可以再放。
:bulb:像這樣,是不是就好理解這兩個概念了