防抖与节流

74 阅读2分钟

防抖和节流

防抖与节流的原理

本质上是优化高频率执行代码的一种手段

如:浏览器的 resizescrollkeypressmousemove 等事件在触发时,会不断地调用绑定在事件上的回调函数,极大地浪费资源,降低前端性能

为了优化体验,需要对这类事件进行调用次数的限制,对此我们就可以采用 防抖(debounce)  和 节流(throttle)  的方式来减少调用频率

定义

  • 节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
  • 防抖: n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时

一个经典的比喻:

想象每天上班大厦底下的电梯。把电梯完成一次运送,类比为一次函数的执行和响应

假设电梯有两种运行策略 debounce 和 throttle,超时设定为15秒,不考虑容量限制

电梯第一个人进来后,15秒后准时运送一次,这是节流

电梯第一个人进来后,等待15秒。如果过程中又有人进来,15秒等待重新计时,直到15秒后开始运送,这是防抖

代码实现

// 使用
function showTop() {
  var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  console.log("滚动条位置:" + scrollTop);
}
window.onscroll = debounce(showTop, 1000); 
window.onscroll = throttle(showTop, 1000);

// ******************代码实现******************
function throttle(func, delay) {
  let timer;
  return function (...args) {
    if (timer) return;
    timer = setTimeout(() => {
      func.apply(this, args);
      clearTimeout(timer);
    }, delay);
  };
}

function debounce(func, delay) {
  let timer;
  return function (...args) {
    if (timer) return clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(this, args);
    }, delay);
  };
}

几个问题

为什么使用高阶函数(函数嵌套)

通过使用方法 debounce(showTop, 1000)可以看拿出必须使用函数嵌套

为什么if (timer) return clearTimeout(timer);

这样第二次点击就会取消上一次的点击效果,和防抖定义相符合 "n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时"

为什么 func.apply(this, args);使用apply

根据用法可以看出,throttle(showTop, 1000); 要改变this指向