防抖和節流

ed就是埃德發表於2024-07-18

1. 防抖,回城-執行完成區間計時的那一次

觸發事件時開始計時,計時結束後執行事件處理。當計時未結束再次觸發事件,則清除計時器並重新計時。

思路:利用閉包,儲存回撥函式的計時器。判斷計時器是否存在,是-清除原計時器。在計時器內呼叫事件處理函式。

注意:這裡要搞清楚返回的匿名函式才是繫結的點選事件,而非 debounce 函式。匿名函式可以訪問父函式 debounce 宣告的 timer,每次呼叫匿名函式時,timer 的資料得到保留。

<button>防抖-計時器</button>
<button clss="notTimer">防抖-非計時器</button>

// 使用計時器
let btn = document.querySelector('button');
btn.addEventListener('click', debounce(handler));
// 事件處理函式
function handler(e) {
  console.log(e);			//未傳入引數時為undefine | 傳參後:PointerEvent 
  console.log(this);	    //未修改時為window | 修改this後:<button>防抖-計時器</button>
}
// 防抖函式
function debounce(fn) {
  let timer;
  // 新的事件會重新整理舊的事件,直到最後一件事等待1s後執行
  return function (e) {			// 返回作為回撥事件
    let _this = this;		// 注意:計時器的this只能指向window,用箭頭函式可繼承父業(es6)
    if (timer) clearTimeout(timer);
    timer = setTimeout(function () {
      // 傳入函式呼叫,提高可複用性
      fn.call(_this, e); //!修改this,得去記,得去用啊寶寶:call/bind/apply
    }, 1000)
  }
}

也可以用節流的計時方式。

// 不使用計時器
let btn1 = document.querySelector('.notTimer');
btn1.addEventListener('click', (function () {
    let currTime = Date.now();
    return function (e) {
      let nowTime = Date.now();
      if (nowTime - currTime < 3000) { // 時效內點選,重新整理計時器
          currTime = nowTime;
          return;
      }
      // 呼叫處理函式
      console.log(e)
      console.log(this)
      currTime = nowTime; // 處理完畢,重新整理計時器
    }
})())

2. 節流,cd-區間內只執行第一次,禁止執行第二次

觸發事件後立即執行事件處理,並開始計時,計時結束前,觸發事情不執行事件處理。(合理來說應該是直到第一個執行完畢,可以設定標記,執行完修改標記,作為鎖)

思路:記錄第一次執行呼叫的時間戳,超時才能執行下一次呼叫,並重置起始時間。

window.addEventListener('scroll', throttle(handlerScroll, 1000));
// 事件處理函式
function handlerScroll(e) {
  console.log(e);
  console.log(this);
}
// 節流函式
function throttle(fn, delay) {
  let prevTime = Date.now();
  return function (e) {
    let nowTime = Date.now();
    if (nowTime - prevTime > delay) { // 區間計時結束,執行處理,並重新整理起始時間
      fn.apply(this, e);
      prevTime = Date.now();
    }
  }
}

相關文章