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