1. 程式人生 > 程式設計 >javascript的防抖節流函式解析

javascript的防抖節流函式解析

目錄
  • 防抖節流函式的解析
    • 認識防抖和節流函式
    • 認識防抖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
    }
    

    總結

    本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注我們的更多內容!