防抖 节流_防抖节流与前端性能优化
在我們日常的開發中經常會用到一些容易被反復觸發的事件。比如:scroll、resize、鼠標事件(mousemove,mouseover等)、鍵盤事件(keyup、keydown)。
頻繁觸發回調導致的大量計算會引發頁面的抖動甚至卡頓。為了規避這種情況,我們需要一些手段來控制事件被觸發的頻率。就是在這樣的背景下,throttle(事件節流)和 debounce(事件防抖)出現了。
“節流”與“防抖”的本質
這兩個東西都以閉包的形式存在。
它們通過對事件對應的回調函數進行包裹、以自由變量的形式緩存時間信息,最后用 setTimeout 來控制事件的觸發頻率。
Debounce
防抖的概念其實是從機械開關和繼電器的“去彈跳”(Debounce)衍生 出來的,基本思路就是把多個信號合并為一個信號。
手機拍照也有相似的概念,在拍照的時候手如果拿不穩晃的時候拍照,一般手機是拍不出好照片的,因此智能手機是在你按一下的時候連續拍許多張, 能過合成手段,生成一張,也就是我們平常說的HDR。翻譯成JS就是,事件內的N個動作會被忽略,只有事件后由程序觸發的動作才是有效的。
將目標方法(動作)包裝在setTimeout里面,然后這個方法是一個事件的回調函數,如果這個回調一直連續執行,那么這些動作就一直不執行。為什么不執行呢,我們搞了一個clearTimeout,這樣setTimeout里的方法就不會執行! 為什么要clearTimeout呢,我們就需要將事件內的連續動作刪掉嘛!待到用戶不觸發這事件了。那么setTimeout就自然會執行這個方法。那么這個方法用在什么地方呢,就是用于input輸入框架的格式驗證,假如只是驗證都是字母也罷了,太簡單了,不怎么耗性能,如果是驗證是否身份證,這性能消耗大,你可以隔170ms才驗證一次,或者更長的時間。這時就需要這個東西。或者你這個是自動校驗,需要將已有的輸入數據往后端拉一個列表,頻繁的交互,后端肯定耗不起,這時也需要這個,如隔350ms。下面我們來實際寫一個防抖:
//?fn是我們需要包裝的事件回調,?delay是每次推遲執行的等待時間function?debounce(fn,?delay)?{
??//?定時器
??let?timer?=?null
??//?將debounce處理結果當作函數返回
??return?function?()?{
????//?保留調用時的this上下文
????let?context?=?this
????//?保留調用時傳入的參數
????let?args?=?arguments
????//?每次事件被觸發時,都去清除之前的舊定時器,這里是閉包,timer變量必須清除
????if(timer)?{
????????clearTimeout(timer)
????}
????//?設立新定時器
????timer?=?setTimeout(function?()?{
??????fn.apply(context,?args)
????},?delay)
??}
}
//?用debounce來包裝scroll的回調
const?better_scroll?=?debounce(()?=>?console.log('觸發了滾動事件'),?1000)
document.addEventListener('scroll',?better_scroll)
Throttle
節流的概念可以想象一下水壩,你建了水壩在河道中,不能讓水流動不了,你只能讓水流慢些。換言之,你不能讓用戶的方法都不執行。如果這樣干,就是debounce了。為了讓用戶的方法在某個時間段內只執行一次,我們需要保存上次執行的時間點與定時器。下面來實際寫一個節流:
//?fn是我們需要包裝的事件回調,?interval是時間間隔的閾值????????由于是閉包,last值可以保存上次的觸發時間,不會重置為0if?(now?-?last?>=?interval)?{用 Throttle 來優化 Debounce
debounce 的問題在于它“太有耐心了”。試想,如果用戶的操作十分頻繁——他每次都不等 debounce 設置的 delay 時間結束就進行下一次操作,于是每次 debounce 都為該用戶重新生成定時器,回調函數被延遲了不計其數次。頻繁的延遲會導致用戶遲遲得不到響應,用戶同樣會產生“這個頁面卡死了”的觀感。
為了避免弄巧成拙,我們需要借力 throttle 的思想,打造一個“有底線”的 debounce——等你可以,但我有我的原則:delay 時間內,我可以為你重新生成定時器;但只要delay的時間到了,我必須要給用戶一個響應。這個 throttle 與 debounce “合體”思路,已經被很多成熟的前端庫應用到了它們的加強版 throttle 函數的實現中:
//?fn是我們需要包裝的事件回調,?delay是時間間隔的閾值???????timer?=?setTimeout(
?如果覺得本文對你有所幫助,不如點個在看再走。
總結
以上是生活随笔為你收集整理的防抖 节流_防抖节流与前端性能优化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle客户端三种连接,客户端连接O
- 下一篇: 怎么打开网络访问 计算机共享,电脑只要打