JavaScript 五十問——認真聊一聊去抖與節流

前言

不管是面試仍是在討論瀏覽器優化過程當中,都會涉及到去抖動和節流的問題。
總的來講,這兩者是一種限制事件觸發頻率的方式。不一樣的是,節流會指定事件觸發的時間間隔;而去抖動會指定事件不觸發的時間間隔。從結果上來看,節流下降了時間處理的敏感度;而去抖對從觸發事件先存儲起來,等到超過指定事件間隔後,一塊兒發送。
愈來愈暈,直接上代碼:
HTML面試

<input type="text" oninput="fatch()">

這裏有一個供用戶搜索使用的input標籤,有一個input事件會觸發的處理函數fatch,這個fatch會根據input的value值向後臺去請求聯想詞。
上面代碼思路是沒有問題的,可是若是不作觸發限制的話,可能會產生大量的http請求,而這些請求裏面不少可能意義不大,爲咱們的優化提供了空間;下面,我就採用節流和去抖兩種思路來解決這個問題。(通常針對input這種狀況,使用去抖解決;這裏只是方便作代碼說明)瀏覽器

節流

function jieliu (func, time){//func 執行函數, time 時間間隔
  let lastRun = null
  
  return function(){
    const now = new Date()
    if(now - lastRun > time){
      func(...arguments)
      lastRun = now
    }
  }
}


const listener = jieliu(function(value){//監聽函數,指定間隔時間
  console.log(value)
}, 1000)

const input = document.querySelector("input")
//調用方法
input.addEventListener("input", function(event){
     listener(event.target.value)
})

以上是比較簡單的節流實現以及基本的調用方式;使用閉包是爲了保存每一次執行的lastRun。基本實現了限制請求頻率的需求,但忽略了最後一個的觸發。
改進以下:閉包

function jieliu (func, time){// 觸發時間間隔>time 發送請求
  let lastRun = null
  let timeout = undefined
  return function(){
    const self = this; 
    const now = new Date()
    if(now - lastRun > time){
      if(timeout){
        clearTimeout(timeout)
        timeout = undefined
      }
      func.apply(self, arguments)
      lastRun = now
    }
    else{
      if(!timeout){
        timeout = setTimeout(func.apply(self, arguments), time)
      }
    }
  }
}

加入timeout,判斷是不是最後一次請求。app

去抖動

function qudou(func, time){
  let timeout = undefined
  
  return function(){
    const argu = arguments
    const self = this

    if(timeout){
      clearTimeout(timeout)
      timeout = undefined
    }else{
        timeout = setTimeout(func.apply(this, arguments), time)
    }
  }
}

以上簡單實現去抖動,一樣,最後一次事件不可以觸發處理函數。函數

改進以下:優化

function qudou(func, time){//判斷連續time時間內不觸發,發送func請求
  let timeout = undefined;
  let lastRun = null
  return function(){
    const self = this
    const now = new Date()
    if(now - lastRun > time){
      func.apply(self, arguments)
    }
    else {
      if(!timeout){
        timeout = setTimeout(func.apply(self, arguments), time)
      }
      else {
        clearTimeout(timeout)
        timeout = undefined
      }
    }
    lastRun = new Date()
  }
}

總結

通篇寫下來,節流主要的實現方式仍是經過對比「now」與「lastRun」的時間差,進而減小處理函數的調用次數;而防抖仍是經過settimeout來延緩處理函數的調用時機,進而把屢次觸發的結果彙總一塊兒調用處理函數。this

後記

節流與去抖動兩種方案仍是有很大不一樣的,不少人包括我都很容易搞混。若是你們有更好的解決方案或者須要討論的地方,歡迎在踊躍留言!code

相關文章
相關標籤/搜索