防抖和节流

44 阅读1分钟

防抖

防抖的定义

防抖 确保特定时间内无论触发了多少次函数,都只执行一次。 在一些高频触发的事件,比如滚动、输入、点击等场景非常有用,避免函数的过度执行,造成卡顿

防抖实现
// 函数
export function debounce(fn: Function, delay: number = 1000) {
  // 定时器 使用闭包来存储一个状态,保证每次获取的都是同一个定时器
  let timer: any = null;
  // 执行debounce函数,返回一个函数,这个函数是一个闭包,保留了timer和fn
  return function (...args: any[]) {
    // 单位时间内重复执行,清除定时器,重写开始计时
    if (timer) {
      clearTimeout(timer);
    }
    // 开始计时
    timer = setTimeout(() => {
      fn(...args);
      // 函数执行完毕,清除定时器
      timer = null;
    }, delay);
  };
}
// 装饰器
function debounce(delay: number) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    let timerId: NodeJS.Timeout;

    descriptor.value = function (...args: any[]) {
      clearTimeout(timerId);
      timerId = setTimeout(() => originalMethod.apply(this, args), delay);
    };

    return descriptor;
  };
防抖使用

举例当浏览器窗口发生变化时,在控制台输出resize

// 函数使用
const a = debounce(() => {
  console.log("resize");
}, 1000);
window.addEventListener("resize", a);
// 装饰器使用
class Test {
  @debounce2(1000)
  resize2() {
    console.log("resize2");
  }
  init() {
    window.addEventListener("resize", this.resize2);
  }
}
const b = new Test();
b.init();

节流

节流的定义

函数多次执行,确保每间隔特定时间执行一次

节流的实现
// 函数使用
export function throttle(fn: Function, delay: number = 1000) {
  let timer: any = null;
  return function (...args: any[]) {
    if (timer) {
      return;
    }
    timer = setTimeout(() => {
      fn(...args);
      timer = null;
    }, delay);
  };
}
// 使用装饰器
export function throttle2(delay: number = 1000){
  return function(target: any, key: string, descriptor: PropertyDescriptor){
    let timer: any = null;
    const fn = descriptor.value;
    descriptor.value = function(...args: any[]){
      if(timer){
        return;
      }
      timer = setTimeout(()=> {
        fn(...args);
        timer = null;
      }, delay);
    }
  }
}

节流的使用
// 函数的使用
const t =  throttle(() => {
  console.log("resize");
}, 1000);
window.addEventListener("resize", t);
// 装饰器的使用
class Test2 {
  @throttle2(1000)
  resize2() {
    console.log("resize2");
  }
  init() {
    window.addEventListener("resize", this.resize2);
  }
}
const c = new Test2();
c.init();