深入理解防抖函数:实现一个完美的 JavaScript 防抖类

268 阅读3分钟

在前端开发中,防抖函数(Debounce)是一个常用的工具,特别适用于限制某个函数在短时间内的频繁调用。例如,当用户快速输入时,我们不希望每个按键都触发搜索请求,而是希望在用户停止输入后的一段时间内只发起一次请求。防抖函数能帮助我们实现这一需求。

本文将带你深入理解防抖函数的原理,并提供一个功能完备的 JavaScript 防抖函数类,支持立即执行选项、手动取消以及执行次数统计等功能。

什么是防抖函数?

防抖函数的基本原理是:在连续触发事件的过程中,只在最后一次事件触发后的一段时间内调用目标函数。这样可以有效减少高频率事件的处理次数,提升性能表现。

防抖函数的常见应用场景

  1. 表单输入:在用户输入时频繁触发输入事件,但我们只希望在用户停止输入后再进行处理。
  2. 滚动事件:在页面滚动过程中,滚动事件会被频繁触发,防抖可以减少滚动事件的处理次数。
  3. 窗口调整:用户调整窗口大小时会频繁触发 resize 事件,防抖可以减少处理次数。

实现一个完美的防抖函数类

以下是一个功能完备的防抖函数类的实现,具有立即执行选项、手动取消以及执行次数统计的功能:

 class Debounce {
   constructor(func, wait = 300, immediate = false) {
     this.func = func; // 要防抖的函数
     this.wait = wait; // 防抖的等待时间
     this.immediate = immediate; // 是否立即执行
     this.timeout = null; // 保存定时器的引用
     this.callCount = 0; // 记录实际调用次数
 ​
     // 绑定 this 到类的方法上
     this.debounced = this.debounced.bind(this);
     this.cancel = this.cancel.bind(this);
     this.resetCallCount = this.resetCallCount.bind(this); // 新增重置调用次数方法
   }
 ​
   // 核心防抖函数逻辑
   debounced(...args) {
     // 如果存在定时器,清除它
     if (this.timeout) clearTimeout(this.timeout);
 ​
     if (this.immediate) {
       // 如果立即执行模式
       const callNow = !this.timeout; // 如果没有定时器,则立即执行
       this.timeout = setTimeout(() => {
         this.timeout = null; // 等待时间过后重置定时器
       }, this.wait);
       if (callNow) {
         this.callCount++; // 增加调用次数
         this.func.apply(this, args); // 调用目标函数
       }
     } else {
       // 普通防抖模式
       this.timeout = setTimeout(() => {
         this.callCount++; // 增加调用次数
         this.func.apply(this, args); // 调用目标函数
       }, this.wait);
     }
   }
 ​
   // 取消防抖计时器
   cancel() {
     if (this.timeout) {
       clearTimeout(this.timeout); // 清除定时器
       this.timeout = null; // 重置定时器引用
     }
   }
 ​
   // 获取实际调用次数
   getCallCount() {
     return this.callCount;
   }
 ​
   // 重置调用次数
   resetCallCount() {
     this.callCount = 0;
   }
 }

使用示例

我们可以通过以下示例来演示如何使用这个防抖函数类:

const debouncedFunction = new Debounce((msg) => {
   console.log(msg);
 }, 1000);
 ​
 document.getElementById("button").addEventListener("click", () => {
   debouncedFunction.debounced("Button clicked");
 });
 ​
 // 取消防抖
 // debouncedFunction.cancel();
 ​
 // 获取调用次数
 // console.log(debouncedFunction.getCallCount());
 ​
 // 重置调用次数
 // debouncedFunction.resetCallCount();

在这个示例中,当用户点击按钮时,debouncedFunction.debounced 会被调用,但实际的目标函数只会在最后一次点击后的 1 秒后执行。你还可以通过调用 debouncedFunction.cancel 来手动取消防抖计时器,通过 debouncedFunction.getCallCount 来获取目标函数实际被调用的次数。

结语

通过本文的介绍,我们不仅理解了防抖函数的原理,还学习了如何实现一个功能完备的防抖函数类。这个类不仅满足防抖的基本需求,还提供了更多的控制和统计功能,适用于各种前端开发场景。

希望这个防抖函数类能为你的项目带来帮助。如果你有任何疑问或建议,欢迎在评论区留言讨论。