事件的防抖和節流

事件的防抖和節流

防抖和節流函數是咱們常常用到的函數,在實際的開發過程當中,如 scroll、resize、click、鍵盤等事件很容易被屢次觸發,頻繁的觸發回調會致使頁面卡頓和抖動,爲了不這種狀況,須要使用節流和防抖的方法來減小無用的操做和網絡請求,也是面試中常常遇到的問題,須要緊緊掌握。前端

防抖和節流的本質

都是閉包的形式存在的.面試

他們經過對事件的回調函數進行包裹、以保存自由變量的形式來緩存時間信息,最後使用 setTimeout 來控制事件的觸發頻率。數組

節流:第一我的說了算

節流(Throttle)的中心思想在於:在某段時間內不過你觸發了多少次,我都只認第一次,而且在計時結束時給出響應。緩存

/**
 * 函數節流
 * 做用:一段時間內的屢次操做,只按照第一次觸發開始計算,並在計時結束時給予響應。
 * 場景:如輸入搜索功能
 * @param fn 須要進行節流操做的事件函數
 * @param interval 間隔時間
 * @returns {Function}
 */
function throttle(fn, interval = 500) {
  let last = 0;
  return function (...args) {
    let now = +new Date();
    if (now - last > interval) {
      last = now;
      fn.call(this, args);
    }
  };
}
/**
 * 步驟
 * 接受一個函數,和一個觸發間隔時間,時間默認是 500ms
 * 默認賦值爲0
 * 將多個參數解構爲一個參數數組
 * 記錄本次觸發回調的時間
 * 判斷上次觸發的時間和本次之間的間隔是否大於咱們設定的閾值
 * 將本次觸發的時間賦值給last,用於下次判斷
 * 使用call調用傳入的回調函數,並傳入參數
 *
 */

使用:在 onScorll 中使用節流網絡

// 使用 throttle 來包裝 scorll 的回調函數,設置間隔時間爲1s
const better_scorll = throttle(() => {
  console.log("觸發了滾動事件");
}, 1000);
document.addEventListenner("scorll", better_scorll);
// 1s內,不管觸發多少次,都只從第一次觸發以後的1s後給出響應。

防抖:最後一我的說了算

防抖的中心思想在於:我會等你到底。在某段時間內,無論你觸發了多少次回調,我都只認最後一次閉包

/**
 * 函數防抖
 * 做用:一段時間內的屢次操做,只執行最後一次。
 * 場景:如點擊登陸/註冊/支付等按鈕時
 * @param fn 須要進行防抖操做的事件函數
 * @param delay 延遲時間
 * @returns {Function}
 */
function debounce(fn, delay = 500) {
  let timer = null;
  return function (...args) {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      fn.call(this, args);
    }, delay);
  };
}
/**
 * 接受一個函數,和一個觸發間隔時間,時間默認是 500ms
 * 定時器 id 默認賦值爲null
 * 將多個參數解構爲一個參數數組
 * 判斷timer是否存在,如存在就取消定時器
 * 而後建立一個新的定時器,並將id賦值給timer
 * 而後若是再次點擊重複上面的操做,一直到delay時間內沒點時,定時器執行
 * 執行時:使用call調用傳入的回調函數,並傳入參數
 *
 */

使用:在 onScorll 中使用防抖函數

// 用debounce來包裝scroll的回調
const better_scroll = debounce(() => console.log("觸發了滾動事件"), 1000);
document.addEventListener("scroll", better_scroll);

用 Throttle 來優化 Debounce

debounce 的問題是它太有耐心了,試想,若是用戶的操做十分頻繁————他每次都不等 debounce 設置的 delay 的時間結束就進行下一次操做,因而每次 debounce 都會爲用戶從新生成定時器,回調函數被延遲了一次又一次,用戶遲遲得不到響應,用戶也會對這個頁面產生「頁面卡死」了的觀感。優化

爲了不弄巧成拙,咱們須要借力 Throttle 的思想,打造一個「有底線」的 debounce ,等你能夠,但我有個人原則:delay 時間內,我能夠爲你從新生成定時器,可是隻要 delay 時間一到,我就必須給用戶一個響應。this

這種 Throttle 和 debounce 合體的思想,已經被不少成熟的前端庫應用到他們的增強版 throttle 函數中了。code

/**
 * 增強版節流函數
 * 做用:delay時間內的屢次操做將會從新生成定時器,但只要delay時間一到就執行一次。
 * 場景:如點擊登陸/註冊/支付等按鈕時
 * @param fn 須要進行防抖操做的事件函數
 * @param delay 延遲時間
 * @returns {Function}
 */
function throttle(fn, delay = 500) {
  let last = 0;
  let timer = null;
  return function (...args) {
    let now = +new Date();
    if (now - last < delay) {
      // 若是間隔時間小於咱們設定的閾值,則從新生成一個定時器
      if (timer) clearTimeout(timer);
      timer = setTimeout(() => {
        last = now;
        fn.call(this, args);
      }, delay);
    } else {
      // 若是 間隔時間大於設定的閾值,就執行一次。
      last = now;
      fn.call(this, args);
    }
  };
}
/**
 * 接受一個函數和延遲時間,延遲時間默認是500ms
 * 定義一個開始執行的時間戳和定時器id,賦予默認值
 * 返回一個函數,並將參數轉爲數組。
 * 函數內,拿到當前的時間戳
 * 判斷,是否小於間隔時間:
 * 小於:則清楚定時器,而後從新生成定時器。定時器內直接賦值,而後call函數,
 * 大於:直接賦值,而後call函數,
 */

使用:在 onScorll 中使用增強版 throttle

// 用throttle來包裝scroll的回調
const better_scroll = throttle(() => console.log("觸發了滾動事件"), 1000);
document.addEventListener("scroll", better_scroll);
相關文章
相關標籤/搜索