实现防抖函数

85 阅读2分钟

什么是防抖

防抖就是在触发事件后,不会立即执行,而是在规定时间以后才会执行;
如果在规定时间内再次触发事件,那么会重新开始计时。

应用场景

  • 表单验证
  • 按钮提交
  • 输入框查询
  • scroll 事件滚动触发
  • 浏览器窗口缩放,resize 事件

实现功能

  1. 绑定的是一个 function,所以要 return 一个 function
  2. this 指向,如果不用箭头函数,还要在定时器外部绑定 this
  3. arguments 获取参数,如果不用箭头函数,还要在定时器外部绑定 arguments
  4. 增加条件判断是否立即执行(触发即执行,然后 n 秒内触发不执行,n 秒后触发再次立即执行)
  5. 返回值(如果立即执行,可以获取返回值)
  6. 取消防抖(cancel 方法,清除定时器,为了避免闭包导致的内存泄漏,再把 timer 设置为 null)

基础版

// 基础版,实现了触发事件,延迟调用功能;
function debounce(fn, wait) {
  let timer;
  
  return function () {
    if (timer) clearTimeout(timer);
    const _this = this; // 箭头函数可以不用绑定 this
    const args = arguments;
    timer = setTimeout(() => {
      fn.apply(_this, args);
    }, wait);
  };
  
}

进阶版

// 进阶版,增加了判断是否立即执行操作,如果立即执行,接受返回值;
function debounce(fn, wait, immediate) {
  let timer, result;
  
  return function () {
    if (timer) clearTimeout(timer);
    const _this = this;
    const args = arguments;
    
    if (immediate) {
        if (!timer) result = fn.apply(_this, args);
        timer = setTimeout(() => {
            timer = null;
        }, wait);
    } else {
      timer = setTimeout(() => {
        fn.apply(_this, args);
      }, wait);
    }
    
    return result;
  };
  
}

增强版

// 增强版,增加了取消防抖功能,调用 cancel 方法;
function debounce(fn, wait, immediate) {
  let timer, result;
  
  function debounced() {
    if (timer) clearTimeout(timer);
    const _this = this;
    const args = arguments;
    
    if (immediate) {
      if (!timer) result = fn.apply(_this, args);
      timer = setTimeout(() => {
        timer = null;
      }, wait);
    } else {
      timer = setTimeout(() => {
        fn.apply(_this, args);
      }, wait);
    }
    
    return result;
  }
  
  debounced.cancel = function () {
    clearTimeout(timer);
    timer = null;
  };
  
  return debounced;
}

验证

<input type="text" id="search">
<button id="cancel">取消防抖</button>
const inputEle = document.getElementById("search");
const buttonEle = document.getElementById("cancel");

function searchHandler(e) {
  console.log(e);
  console.log(inputEle.value);
  return "123";
}

let handler = debounce(searchHandler, 10000);

buttonEle.addEventListener("click", handler.cancel);
inputEle.addEventListener("keyup", handler);