javascript的防抖節流函式解析
阿新 • • 發佈:2022-01-17
目錄
- 防抖節流函式的解析
- 認識防抖和節流函式
- 認識防抖debounce函式
- 防抖函式的案例
- 認識節流throttle函式
- 節流函式的應用場景
- 自定義防抖和節流函式
- 總結
防抖節流函式的解析
認識防抖和節流函式
防抖和節流的概念其實最早並不是出現在軟體工程中,防抖是出現在電子元件中,節流出現在流體流動中
- 而是事件驅動的,大量的操作會觸發事件,加入到事件佇列中處理。
- 而對於某些頻繁的事件處理會造成效能的損耗,我們就可以通過防抖和節流來限制事件頻繁的發生;
防抖和節流函式目前已經是前端實際開發中兩個非常重要的函式,也是面試經常被問到的面試題。
但是很多前端開發者面對這兩個功能,有點摸不著頭腦:
- 某些開發者根本無法區分防抖和節流有什麼區別(面試經常會被問到);
- 某些開發者可以區分,但是不知道如何應用;
- 某些開發者會通過一些第三方庫來使用,但是不知道內部原理,更不會編寫;
認識防抖debounce函式
我們用一副圖來理解一下它的過程:
- 當事件觸發時,相應的函式並不會立即觸發,而是會等待一定的時間;
- 當事件密集觸發時,函式的觸發會被頻繁的推遲;
- 只有等待了一段時間也沒有事件觸發,才會真正的執行響應函式;
防抖的應用場景很多:
- 輸入框中頻繁的輸入內容,搜尋或者提交資訊;
- 頻繁的點選按鈕,觸發某個事件;
- 監聽瀏覽器滾動事件,完成某些特定操作;
- 使用者縮放瀏覽器的resize事件;
防抖函式的案例
我們都遇到過這樣的場景,在某個搜尋框中輸入自己想要搜尋的內容:
比如想要搜尋一個MacBook:
- 當我輸入m時,為了更好的使用者體驗,通常會出現對應的聯想內容,這些聯想內容通常是儲存在伺服器的,所以需要一次網路請求;
- 當繼續輸入ma時,再次傳送網路請求;
- 那麼macbook一共需要傳送7次網路請求;
- 這大大損耗我們整個系統的效能,無論是前端的事件處理,還是對於伺服器的壓力;
但是我們需要這麼多次的網路請求嗎?
- 不需要,正確的做法應該是在合適的情況下再發送網路請求;
- 比如如果使用者快速的輸入一個macbook,那麼只是傳送一次網路請求;
- 比如如果使用者是輸入一個m想了一會兒,這個時候m確實應該傳送一次網路請求;
- 也就是我們應該監聽使用者在某個時間,比如500ms內,沒有再次觸發時間時,再發送網路請求;
這就是防抖的操作:只有在某個時間內,沒有再次觸發某個函式時,才真正的呼叫這個函式;
認識節流throttle函式
我們用一副圖來理解一下節流的過程
- 當事件觸發時,會執行這個事件的響應函式;
- 如果這個事件會被頻繁觸發,那麼節流函式會按照一定的頻率來執行函式;
- 不管在這個中間有多少次觸發這個事件,執行函式的頻繁總是固定的;
節流的應用場景:
- 監聽頁面的滾動事件;
- 滑鼠移動事件;
- 使用者頻繁點選按鈕操作;
- 遊戲中的一些設計;
節流函式的應用場景
很多人都玩過類似於飛機大戰的遊戲
在飛機大戰的遊戲中,我們按下空格會發射一個子彈:
- 很多飛機大戰的遊戲中會有這樣的設定,即使按下的頻率非常快,子彈也會保持一定的頻率來發射;
- 比如1秒鐘只能發射一次,即使使用者在這1秒鐘按下了10次,子彈會保持發射一顆的頻率來發射;
- 但是事件是觸發了10次的,響應的函式只觸發了一次;
自定義防抖和節流函式
我們按照如下思路來實現:
防抖基本功能實現:可以實現防抖效果
- 優化一:優化引數和this指向
- 優化二:優化取消操作(增加取消功能)
- 優化三:優化立即執行效果(第一次立即執行)
- 優化四:優化返回值
function debounce(fn,delay,immediate=false,reJjEzKcsultCallback){
let timer=null
// console.log(this)//window
// 定義控制立即執行的變數,false表示沒有執行過
let isInvoke=false
// 真正的處理函式
function _debounce(...args){
// 取消事件執行操作
if(timer) clearTimeout(timer)
// console.log(this)//element元素
if(immediate&&!isInwww.cppcns.comvoke){
const result=fn.apply(this,args)
resultCallback(result)
isInvoke=true
}else{
// 延遲執行
timer=setTimeout(()=>{
const result=fn.apply(this,args)
resultCallback(result)
timer=null
isInvoke=false
},delay)
}
}
// 封裝取消請求
_debounce.cancel=function(){
if(timer) clearTimeout(timer)
timer=null
isInvoke=false
}
return _debounce
}
我們按照如下思路來實現:
節流函式的基本實現:可以實現節流效果
- 優化一:節流最後一次也可以執行
- 優化二:優化新增取消功能
- 優化三:優化返回值問題
functiowww.cppcns.comn throttle(fn,interval,options={leading:true,trailing:false}){ let lastTime=0 const {leading,trailing,resultCallback}=options let timer=null function _throttle(...args){ const nowTime=new Date().getTime() // leading優化 if(!leading&&!lastTime) lastTime=nowTime let remainTime=interval-(nowTime-lastTime) if(remainTime<=0){ if(timer){ clearTimeout(timer) timer=null } // 引數優化 const result=fn.apply(this,args) if(resultCallback) resultCallback(result) lastTime=nowTime return } // 優化trailing if(!timer&&trailing){ timer=setTimeout(()=>{ // 引數優化 const result=fn.apply(this,args) if(resultCallback) resultCallback(result) timer=null lastTime=!leading?0:new Date().getTime() },remainTime) } } _throttle.cancel=function(){ if(timer) clearTimeout(timer) timer = null lastTime = 0 } return _throttle }
總結
本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注我們的更多內容!