手写防抖和节流

76 阅读2分钟

节流,顾名思义,控制水的流量。控制事件发生的频率,如控制为1s发生一次,甚至1分钟发生一次。与服务端(server)及网关(gateway)控制的限流(Rate Limit)类似。

想要了解一个概念,必先了解概念所应用的场景。在 JS 这个世界中,有哪些节流的场景呢:

  1. scroll 事件,每隔一秒计算一次位置信息等。
  2. 浏览器播放事件,每隔一秒计算一次进度信息等。
  3. input 框实时搜索并发送请求展示下拉列表,每隔一秒发送一次请求(也可做防抖)。

代码如下,可以看出来节流重在开关锁timer=null

// 节流可以理解为「倒计时中」
const throttle = (fn, time) => {
  let timer = null; // 设置一个倒计时的计时器
  // 返回一个包装后的节流函数
  return (...args) => {
    if (timer) return; // 如果此时已开始计时则什么都不做
    fn.call(undefined, ...args); // 计时结束,就调用原函数
    // 需要重新设置定时器,并在指定的时间之后清空
    timer = setTimeout(() => {
      timer = null;
    }, time);
  };
};

image.png

image.png

防抖 debounce

防抖,顾名思义,防止抖动,以免把一次事件误认为多次,敲键盘就是一个每天都会接触到的防抖操作。

  1. 登录、发短信等按钮避免用户点击太快,以致于发送了多次请求,需要防抖。
  2. 调整浏览器窗口大小时,resize 次数过于频繁,造成计算过多,此时需要一次到位,就用到了防抖。
  3. 文本编辑器实时保存,当无任何更改操作一秒后进行保存。

代码如下,可以看出来防抖重在清零clearTimeout(timer)

// 防抖可以理解为「响应事件被打断」
const debounce = (fn, time) => {
  let timer = null; // 设置一个计时器
  // 返回一个包装后的防抖函数
  return (...args) => {
    // 如果此时已开始计时,就清空定时器
    if (timer !== null) clearTimeout(timer);
    // 重新设置定时器,并在相应时间执行原函数后清空
    timer = setTimeout(() => {
      fn.call(undefined, ...args);
      timer = null;
    }, time);
  };
};