溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何進(jìn)行javascript的防抖節(jié)流函數(shù)解析

發(fā)布時(shí)間:2022-01-15 14:44:22 來(lái)源:億速云 閱讀:328 作者:柒染 欄目:開(kāi)發(fā)技術(shù)

這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)?lái)有關(guān)如何進(jìn)行javascript的防抖節(jié)流函數(shù)解析,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

防抖節(jié)流函數(shù)的解析

認(rèn)識(shí)防抖和節(jié)流函數(shù)

防抖和節(jié)流的概念其實(shí)最早并不是出現(xiàn)在軟件工程中,防抖是出現(xiàn)在電子元件中,節(jié)流出現(xiàn)在流體流動(dòng)中

  • 而JavaScript是事件驅(qū)動(dòng)的,大量的操作會(huì)觸發(fā)事件,加入到事件隊(duì)列中處理。

  • 而對(duì)于某些頻繁的事件處理會(huì)造成性能的損耗,我們就可以通過(guò)防抖和節(jié)流來(lái)限制事件頻繁的發(fā)生;

防抖和節(jié)流函數(shù)目前已經(jīng)是前端實(shí)際開(kāi)發(fā)中兩個(gè)非常重要的函數(shù),也是面試經(jīng)常被問(wèn)到的面試題

但是很多前端開(kāi)發(fā)者面對(duì)這兩個(gè)功能,有點(diǎn)摸不著頭腦:

  • 某些開(kāi)發(fā)者根本無(wú)法區(qū)分防抖和節(jié)流有什么區(qū)別(面試經(jīng)常會(huì)被問(wèn)到);

  • 某些開(kāi)發(fā)者可以區(qū)分,但是不知道如何應(yīng)用;

  • 某些開(kāi)發(fā)者會(huì)通過(guò)一些第三方庫(kù)來(lái)使用,但是不知道內(nèi)部原理,更不會(huì)編寫(xiě);

認(rèn)識(shí)防抖debounce函數(shù)

我們用一副圖來(lái)理解一下它的過(guò)程:

  • 當(dāng)事件觸發(fā)時(shí),相應(yīng)的函數(shù)并不會(huì)立即觸發(fā),而是會(huì)等待一定的時(shí)間;

  • 當(dāng)事件密集觸發(fā)時(shí),函數(shù)的觸發(fā)會(huì)被頻繁的推遲;

  • 只有等待了一段時(shí)間也沒(méi)有事件觸發(fā),才會(huì)真正的執(zhí)行響應(yīng)函數(shù);

如何進(jìn)行javascript的防抖節(jié)流函數(shù)解析

防抖的應(yīng)用場(chǎng)景很多:

  • 輸入框中頻繁的輸入內(nèi)容,搜索或者提交信息;

  • 頻繁的點(diǎn)擊按鈕,觸發(fā)某個(gè)事件;

  • 監(jiān)聽(tīng)瀏覽器滾動(dòng)事件,完成某些特定操作;

  • 用戶縮放瀏覽器的resize事件;

防抖函數(shù)的案例

我們都遇到過(guò)這樣的場(chǎng)景,在某個(gè)搜索框中輸入自己想要搜索的內(nèi)容

比如想要搜索一個(gè)MacBook:

  • 當(dāng)我輸入m時(shí),為了更好的用戶體驗(yàn),通常會(huì)出現(xiàn)對(duì)應(yīng)的聯(lián)想內(nèi)容,這些聯(lián)想內(nèi)容通常是保存在服務(wù)器的,所以需要一次網(wǎng)絡(luò)請(qǐng)求;

  • 當(dāng)繼續(xù)輸入ma時(shí),再次發(fā)送網(wǎng)絡(luò)請(qǐng)求;

  • 那么macbook一共需要發(fā)送7次網(wǎng)絡(luò)請(qǐng)求;

  • 這大大損耗我們整個(gè)系統(tǒng)的性能,無(wú)論是前端的事件處理,還是對(duì)于服務(wù)器的壓力;

但是我們需要這么多次的網(wǎng)絡(luò)請(qǐng)求嗎?

  • 不需要,正確的做法應(yīng)該是在合適的情況下再發(fā)送網(wǎng)絡(luò)請(qǐng)求;

  • 比如如果用戶快速的輸入一個(gè)macbook,那么只是發(fā)送一次網(wǎng)絡(luò)請(qǐng)求;

  • 比如如果用戶是輸入一個(gè)m想了一會(huì)兒,這個(gè)時(shí)候m確實(shí)應(yīng)該發(fā)送一次網(wǎng)絡(luò)請(qǐng)求;

  • 也就是我們應(yīng)該監(jiān)聽(tīng)用戶在某個(gè)時(shí)間,比如500ms內(nèi),沒(méi)有再次觸發(fā)時(shí)間時(shí),再發(fā)送網(wǎng)絡(luò)請(qǐng)求;

這就是防抖的操作:只有在某個(gè)時(shí)間內(nèi),沒(méi)有再次觸發(fā)某個(gè)函數(shù)時(shí),才真正的調(diào)用這個(gè)函數(shù);

認(rèn)識(shí)節(jié)流throttle函數(shù)

我們用一副圖來(lái)理解一下節(jié)流的過(guò)程

  • 當(dāng)事件觸發(fā)時(shí),會(huì)執(zhí)行這個(gè)事件的響應(yīng)函數(shù);

  • 如果這個(gè)事件會(huì)被頻繁觸發(fā),那么節(jié)流函數(shù)會(huì)按照一定的頻率來(lái)執(zhí)行函數(shù);

  • 不管在這個(gè)中間有多少次觸發(fā)這個(gè)事件,執(zhí)行函數(shù)的頻繁總是固定的;

如何進(jìn)行javascript的防抖節(jié)流函數(shù)解析

節(jié)流的應(yīng)用場(chǎng)景:

  • 監(jiān)聽(tīng)頁(yè)面的滾動(dòng)事件;

  • 鼠標(biāo)移動(dòng)事件;

  • 用戶頻繁點(diǎn)擊按鈕操作;

  • 游戲中的一些設(shè)計(jì);

節(jié)流函數(shù)的應(yīng)用場(chǎng)景

很多人都玩過(guò)類似于飛機(jī)大戰(zhàn)的游戲

在飛機(jī)大戰(zhàn)的游戲中,我們按下空格會(huì)發(fā)射一個(gè)子彈:

  • 很多飛機(jī)大戰(zhàn)的游戲中會(huì)有這樣的設(shè)定,即使按下的頻率非常快,子彈也會(huì)保持一定的頻率來(lái)發(fā)射;

  • 比如1秒鐘只能發(fā)射一次,即使用戶在這1秒鐘按下了10次,子彈會(huì)保持發(fā)射一顆的頻率來(lái)發(fā)射;

  • 但是事件是觸發(fā)了10次的,響應(yīng)的函數(shù)只觸發(fā)了一次;

如何進(jìn)行javascript的防抖節(jié)流函數(shù)解析

自定義防抖和節(jié)流函數(shù)

我們按照如下思路來(lái)實(shí)現(xiàn):

防抖基本功能實(shí)現(xiàn):可以實(shí)現(xiàn)防抖效果

  • 優(yōu)化一:優(yōu)化參數(shù)和this指向

  • 優(yōu)化二:優(yōu)化取消操作(增加取消功能)

  • 優(yōu)化三:優(yōu)化立即執(zhí)行效果(第一次立即執(zhí)行)

  • 優(yōu)化四:優(yōu)化返回值

function debounce(fn,delay,immediate=false,resultCallback){
  let timer=null
  // console.log(this)//window
  // 定義控制立即執(zhí)行的變量,false表示沒(méi)有執(zhí)行過(guò)
  let isInvoke=false
  // 真正的處理函數(shù)
  function _debounce(...args){
    // 取消事件執(zhí)行操作
    if(timer) clearTimeout(timer)
    // console.log(this)//element元素
    if(immediate&&!isInvoke){
      const result=fn.apply(this,args)
      resultCallback(result)
      isInvoke=true
    }else{
      // 延遲執(zhí)行
      timer=setTimeout(()=>{
        const result=fn.apply(this,args)
        resultCallback(result)
        timer=null
        isInvoke=false
      },delay)
    }
  }
  // 封裝取消請(qǐng)求
  _debounce.cancel=function(){
    if(timer) clearTimeout(timer)
    timer=null
    isInvoke=false
  }
  return _debounce
}

我們按照如下思路來(lái)實(shí)現(xiàn):

節(jié)流函數(shù)的基本實(shí)現(xiàn):可以實(shí)現(xiàn)節(jié)流效果

  • 優(yōu)化一:節(jié)流最后一次也可以執(zhí)行

  • 優(yōu)化二:優(yōu)化添加取消功能

  • 優(yōu)化三:優(yōu)化返回值問(wèn)題

function 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優(yōu)化
    if(!leading&&!lastTime) lastTime=nowTime
    let remainTime=interval-(nowTime-lastTime)
    if(remainTime<=0){
      if(timer){
        clearTimeout(timer)
        timer=null
      }
      // 參數(shù)優(yōu)化
      const result=fn.apply(this,args)
      if(resultCallback) resultCallback(result)
      lastTime=nowTime
      return
    } 
    // 優(yōu)化trailing
    if(!timer&&trailing){
      timer=setTimeout(()=>{
        // 參數(shù)優(yōu)化
        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
}

上述就是小編為大家分享的如何進(jìn)行javascript的防抖節(jié)流函數(shù)解析了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI