js 節流函數

在性能優化實踐中,遇到scroll事件,優先須要考慮節流。 節流函數顧名思義,就是要使密集頻繁觸發的函數,按照有規律有節制的過程去執行,那麼背後的原理是什麼?一步步實現吧。性能優化

1 最最最簡單使用場景舉例:監聽屏幕滾動,添加回調函數,要怎麼寫呢?
var num = 0
window.onscroll = function () {

  console.log('回調函數執行' + (++num) + '次')
    
}
複製代碼
效果以下

能夠發現,隨意滾動屏幕,回調函數就會執行不少次,也就是頻繁的觸發着回調函數,因此爲了減小性能開銷,要下降函數執行頻率。
2 若是隻讓滾動事件結束後觸發回調函數,該怎麼作?
var num = 0
var timer = null
var cb = function(){
  console.log('回調函數執行' + (++num) + '次')
}
window.onscroll = function () {
  clearTimeout(timer)
  timer = setTimeout(() => {
    cb()
  }, 1000)
}
複製代碼

能夠看到結果是,在頁面滾動結束的一秒後,控制檯纔會打印結果。
其實window綁定的滾動監聽事件在頁面滾動時候仍是和上面同樣的觸發。只是用來控制檯打印的回調函數,放在setTimeout中去執行。
滾動監聽函數觸發間隔遠遠小於setTimeout的一秒,因此回調函數cb還將來得及執行,就已經被下一次的滾動clearTimeout(timer)了。
只有在滾動結束的前一次觸發,會生成一個setTimeout不會再被清除,也就在滾動結束後一秒執行了cb函數。
那麼這麼寫有什麼問題存在? timer直接被定義在了全局,應該避免。
var num = 0
var cb = function(){
  console.log('回調函數執行' + (++num) + '次')
}
var throttle = function (fn, delay) {
    var timer = null
    return function () {
        clearTimeout(timer);
        timer = setTimeout(function() {
            fn();
        }, delay);
    }
}
window.onscroll = throttle(cb, 1000)
複製代碼
爲何這麼寫能夠避免全局變量污染?仔細看,就是一個閉包。
window.onscroll 綁定的是 throttle(cb, 1000) ,即綁定的是傳入參數爲cb 和 1000,throttle執行後返回的函數。這個函數能夠一直拿到父級做用域下的timer,而在window環境下沒法拿到這個timer變量。也就避免了全局變量污染。
到目前爲止,還只是解決了在滾動結束後觸發回調函數這個問題。而這並非節流。由於上述寫法在不間斷的滾動屏幕過程當中,不會執行回調函數,只有在中止滾動後纔會去執行。這顯然不是節流。那麼須要在滾動過程當中,至少400ms就要觸發一次傳入的回調函數,要如何修改?
var num = 0
var cb = function(){
console.log('回調函數執行' + (++num) + '次')
}
var throttle = function (fn, delay, atleast) {
// 聲明定時器
var timer = null
var previous = null
return function () {
  // 每次頁面滾動時候都會生成新的時間戳
  var now = +new Date()
  // 若是是第一次滾動
  if ( !previous ) previous = now
  // 不斷的滾動,直到時間間隔知足條件,執行回調函數,更新previous,清空定時器
  if ( atleast && now - previous > atleast ) {
    fn();
    previous = now
    clearTimeout(timer)
  // 不知足時間間隔條件,仍是進函數中先清空上次的定時器
  // 並生成新的定時器,
  } else {
    clearTimeout(timer)
    timer = setTimeout(function() {
      fn()
    }, delay);
  }
 }
}
window.onscroll = throttle(cb, 1000, 400)
複製代碼
運行結果以下圖,在頻繁滾動頁面過程當中,每隔400毫秒打印結果,滾動中止後一秒打印結果。

相關文章
相關標籤/搜索