什么是节流 (throttle)? 如何实践节流 (throttle) 函式?

2022年12月11日

💎 加入 E+ 成長計畫 如果你喜歡我們的內容,歡迎加入 E+,獲得更多深入的軟體前後端內容

防抖(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 上追蹤我們