什麼是節流 (throttle)?如何實踐節流 (throttle) 函式?

2022年12月11日

💎 加入 E+ 成長計畫 與超過 300+ 位軟體工程師一同在社群中成長,並且獲得更多的軟體工程學習資源

防抖 (debounce) 和節流 (throttle) 絕對是在考手寫題時最常出現的前幾名,這兩者都能做到優化,但使用情境不太相同,本篇介紹節流(throttle)函式,在這篇文章中會繼續討論防抖。

節流 (throttle) 在做什麼?

節流 (throttle) 指的是,在一段時間內只會執行一次觸發事件的回調 (callback) 函式,若在這之中又有新事件觸發,則不執行此回調函式。

在手寫節流 (throttle) 函式前,我們先來了解節流的使用情境。

監聽滾動事件,是搭配節流的使用場景之一。舉例來說,要判斷使用者是否已經滑動到頁面的 30% 處,當到達時會觸發一些動畫效果,因此,會透過監聽滾動事件時計算是否已到達該位置,但如果只要一滾動就計算會非常消耗性能,透過節流 (throttle) 可以將計算的這個回調函式在固定時間內合併一次被執行。

這裡不適合使用防抖的原因是,防抖只會在事件停止被觸發後的一段時間內被執行一次。因此如果用防抖,當使用者一直滑動頁面,函式就永遠不會被觸發。這邊我們仍想要函式在滑動過程中被觸發,只是不想那麼頻繁被觸發,這種情境下,節流就可以派上用場。

節流函式會接受兩個參數

  • 延遲的時間 (ms)
  • 要執行的回調 (callback) 函式

手寫節流 (throttle) 函式

我們先直接看程式碼,看看你能了解多少。有不懂的地方也不擔心,下面會透過註解,一行行解釋:

function throttle(fn, delay = 500) {
  let timer = null;

  return (...args) => {
    if (timer) return;
    timer = setTimeout(() => {
      fn(...args);
      timer = null;
    }, delay);
  };
}

程式碼註解版本和實際應用

function throttle(fn, delay = 500) {
  let timer = null;

  // throttle 本身會回傳一個函式,透過 ...args 拿到該函式的引數
  return function (...args) {
    // 如果有計時器,表示還在 delay 的秒數內
    // 直接 return,不往下執行程式碼
    if (timer) return;

    // 如果計時器不等於 null,會進到以下邏輯

    // 設定計時器,在 delay 秒數之後,將計時器值為改為 null
    // 如果還不到 delay 的秒數,再執行一次的話
    // 因為 timer 的值不為 null,前面就先 return 不會進到這段邏輯
    // 可以達到 throttle 的目的,將一段時間內的操作,集合成一次執行
    timer = setTimeout(() => {
      timer = null;
    }, delay);

    // 直到時間到了後,timer 變成 null,才能夠執行函式
    // 用 .apply 來呼叫,才能
    fn.apply(this, args);
  };
}

const updateThrottleText = throttle(() => {
  console.log("throttle");
}, 500);

// 如果一直滑動畫面,會固定 500ms console.log('throttle')
window.addEventListener("scroll", () => {
  updateThrottleText();
});
🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們