淺聊函式防抖與節流

小阿鑫發表於2021-07-19

Description

防抖(debounce)

所謂防抖,就是指觸發事件後 n 秒後才執行函式,如果在 n 秒內又觸發了事件,則會重新計算函式執行時間。

防抖型別分為

  1. 非立即執行版
  2. 立即執行版
  3. 合成版本 防抖

防抖應用場景

  • 登入、發簡訊等按鈕避免使用者點選太快,以致於傳送了多次請求
  • 調整瀏覽器視窗大小時,resize 次數過於頻繁,造成計算過多,此時需要一次到位
  • 文字編輯器實時儲存,當無任何更改操作一秒後進行儲存

非立即執行版

非立即執行版的意思是觸發事件後函式不會立即執行,而是在 n 秒後執行,如果在 n 秒內又觸發了事件,則會重新計算函式執行時間。

/**
 * @description: 
 * @param {*} func 觸發的事件
 * @param {*} wait 多少時長才執行事件
 * @return {*}
 */
        function debounce(func, wait) {
            let timeout;
            return function(){
                // 獲取當前作用域和引數
                const context = this;
                const args = [...arguments] 
                // 如果當前timeout 存在
                // 清空定時器,再次等待wait時間過後再次執行事件
                if(timeout) clearTimeout(timeout)
                // 定時執行 傳遞進來的事件
                timeout = setTimeout(()=>{
                    func.apply(context,args)
                },wait)  
            }
        }

立即執行版本

立即執行版的意思是觸發事件後函式會立即執行,然後 n 秒內不觸發事件才能繼續執行函式的效果。

function debounce(func,wait) {
  let timeout;
  return function () {
      const context = this;
      const args = [...arguments];
      if (timeout) clearTimeout(timeout);
      const callNow = !timeout;
      timeout = setTimeout(() => {
          timeout = null;
      }, wait)
      if (callNow) func.apply(context, args)
  }
}

程式碼解析

當 執行 debounce 函式時, 第一次進來時,timeout 為false,所以 callNow 的值 為 true ,那麼它會立即執行 func 函式,這時 timeout 的值 為 true , 當 timeout 值為true 時, 會執行 清空定時器,此時 timeout 又為 false 了 , 這時 callNow 又 為 true ,再次執行 func 函式。

一直迴圈這樣的操作:

timeout false 時,會立刻執行 func 函式。

timeout true 時,它會執行 clearTimeOut ,這時timeout 又為 false, 而 callNow = ! timeout , 就會立刻執行 func 函式了。

合成版本 防抖

通過傳遞 Boolean 來決定執行哪種版本。

  • true 為立即執行版
  • false 為非立即執行版本

debounce(func,1000,true)

/**
 * @desc 函式防抖
 * @param func 函式
 * @param wait 延遲執行毫秒數
 * @param immediate true 表立即執行,false 表非立即執行
 */
function debounce(func, wait, immediate) {
  let timeout;
  return function () {
    const context = this;
    const args = [...arguments];
    if (timeout) clearTimeout(timeout);
    if (immediate) {
      const callNow = !timeout;
      timeout = setTimeout(() => {
        timeout = null;
      }, wait)
      if (callNow) func.apply(context, args)
    }
    else {
      timeout = setTimeout(() => {
        func.apply(context, args)
      }, wait);
    }
  }
}

節流

所謂節流,就是指連續觸發事件但是在 n 秒中只執行一次函式。 節流會稀釋函式的執行頻率。

節流有兩種實現:

  1. 時間戳版本
  2. 定時器版本

節流應用場景

  1. scroll 事件,每隔一秒計算一次位置資訊等
  2. 瀏覽器播放事件,每個一秒計算一次進度資訊等
  3. input 輸入框在搜尋內容時,可以控制多少s 在執行請求,避免多次發起請求,節約效能。

時間戳版本

function throttle(func, wait) {
    var previous = 0;
    return function() {
        let now = Date.now();
        let context = this;
        let args = arguments;
        if (now - previous > wait) {
            func.apply(context, args);
            previous = now;
        }
    }
}

定時器版本

function throttle(func, wait) {
    let timeout;
    return function() {
        let context = this;
        let args = arguments;
        if (!timeout) {
            timeout = setTimeout(() => {
                timeout = null;
                func.apply(context, args)
            }, wait)
        }

    }
}

程式碼解析

當執行 throttle 函式時,timeout 預設為 undefined , 此時, ! timeout true 時,執行 定時器,並且 將 timeout 為 null,即為 false, 再次執行 throttle 函式時, !timeout 又為 true ,再次執行定時器。

**通過 timeout 的狀態來達到節流的控制 **

總結

  • 防抖: 觸發事件後,一定時間後再執行事件,可以 立即執行 也可以 一定時間再執行

  • 節流: 控制流量,在單位時間內只能請求一次,避免多次觸發事件,影響伺服器效能。

結語

❤️關注+點贊+收藏+評論+轉發❤️,原創不易,鼓勵筆者創作更好的文章

關注公眾號 前端自學社群,即可獲取更多前端高質量文章!

關注後回覆關鍵詞“加群”, 即可加入 “前端自學交流群”,共同學習進步。

關注後新增我微信拉你進技術交流群

歡迎關注公眾號,更多精彩文章只在公眾號推送

參考

https://github.com/mqyqingfeng/Blog/issues/26

相關文章