天天看點

淺聊函數防抖與節流

淺聊函數防抖與節流

防抖(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