函數防抖與節流

函數防抖與節流

平常工做中,常常遇到這樣一個問題,在滾動事件中須要作個複雜計算或者實現一個按鈕的防二次點擊操做。javascript

  • 防抖和節流的做用都是防止函數屢次調用。區別在於,假設一個用戶一直觸發這個函數,且每次觸發函數的間隔小於wait,防抖的狀況下只會調用一次,而節流的 狀況會每隔必定時間(參數wait)調用函數。

函數防抖(debounce)

  • 例如在搜索引擎搜索問題的時候,咱們是但願用戶輸入完最後一個字才調用查詢接口,這個時候適用延遲執行的防抖函數,它老是在一連串(間隔小於wait的)函數觸發以後調用。
const debounce = (fn, wait = 800) => {
    let timer = null
    return function() {
      if (timer) clearTimeout(timer)
      timer = setTimeout(() => {
        // 用 .apply 保證 sayHi 裏面的 this 指向事件的調用者,不然指向 window
        fn.apply(this, arguments)
      }, wait);
    }
  }
 
 function sayHi() {
     console.log('防抖成功')
 }
 
let inp = document.querySelector('#input')

inp.addEventListener('input', debounce(sayHi))

複製代碼
  • 上面這個函數有一點缺陷:會存在一種當即執行函數,好比(咱們在點擊 star 的時候,但願是點擊第一次的時候就生效,而不是最後一次生效)。改進以下:
const debounce = (fn, wait = 800, immediate = true) => {
    let timer, context, args

    // 延遲執行函數
    const later = () => setTimeout(() => {
    // 延遲函數執行完畢,清空緩存的定時器序號
      timer = null
      if (!immediate) {
        fn.apply(context, args)
        context = args = null
      }
    }, wait);

    // 返回的函數是每次實際調用的函數
    return function(...params) {
      // 若是沒有建立延遲函數 later, 就建立一個
      if (!timer) {
        timer = later()
        // 如果當即執行函數,則調用函數
        // 不然緩存參數和調用上下文
        if (immediate) {
          fn.apply(this, params)
        } else {
          context = this
          args = params
        }

         // 若是已經有延遲執行函數 (later), 調用的時候清除原來的並從新設定一個
      } else {
        clearTimeout(timer)
        timer = later()
      }
    }
  }

  function sayHi() {
    console.log(this);
    console.log('防抖成功');
  }

  let inp = document.querySelector('#input')

  inp.addEventListener('input', debounce(sayHi))
複製代碼

函數節流(throttle)

  • 防抖動是將屢次執行變爲最後一次執行,節流是將屢次執行變成每隔一段時間執行。
const throttle = (fn, wait = 400) => {
  let canRun = true
  return function (...args) {
    if (!canRun) return
    canRun = false

    setTimeout(() => {
      fn.apply(this, args)
      // 最後在 setTimeout 執行完畢後再把標記設置爲 true (關鍵)表示能夠執行下一次循環了。當定時器沒有執行的時候標記永遠是 false,在開頭被 return 掉
      canRun = true
    }, wait);
  }
}

function sayHi() {
    console.log(this);
    console.log('節流成功');
  }

let inp = document.querySelector('#input')

inp.addEventListener('input', throttle(sayHi))
複製代碼

總結(使用場景):java

函數防抖:npm

  • search搜索聯想,用戶在不斷輸入值時,用防抖來節約請求資源。
  • window觸發resize的時候,不斷的調整瀏覽器窗口大小會不斷的觸發這個事件,用防抖來讓其只觸發一次

函數節流:瀏覽器

  • 鼠標不斷點擊觸發,mousedown(單位時間內只觸發一次);
  • 監聽滾動事件,好比是否滑到底部自動加載更多,用throttle來判斷

PS: 生產環境中,建議用 lodash 中的 debouncethrottle。畢竟那麼多人在用,出現問題的機率會很小。緩存

相關文章
相關標籤/搜索