手写Debounce 防抖函数遇到的坑

最开始写的防抖函数

  function debounce(fn, delay) {
    let timer;
    // 返回一个函数,这个函数会在一个时间区间结束后的 delay 毫秒时执行 fn 函数
    return function () {
      // 保存函数调用时的上下文和参数,传递给 fn
      let context = this
      let args = arguments
      // 每次这个返回的函数被调用,就清除定时器,以保证不执行 fn
      clearTimeout(timer)
      // 当返回的函数被最后一次调用后(也就是用户停止了某个连续的操作),
      // 再过 delay 毫秒就执行 fn
      timer = setTimeout(function () {
        fn.apply(context, args)
      }, delay)
    }
  }

写两个按钮来执行

<input type="button" value="触发按钮" onclick="btnclick()"/>
<input id="btn" type="button" value="监听按钮"/>

这里 问题就来了 比如点击两次 这样做的话就会出现 2秒之后 打印2次console

  function btnclick() {
    debounce(function () {
      console.log('触发按钮的点击事件')
    }, 1000)()
  }

但是下面这样写就是正确的 连续点击两次 最后一次点击两秒之后打印console

  let btn = document.getElementById('btn')
  btn.addEventListener('click', debounce(() => {
    console.log('监听按钮')
  }, 1000))

这里困惑了很久才发现 实际上事件监听相当于是吧debounce函数的返回值先拿到 再在点击的时候执行这个返回函数

而触发按钮是每次点击都会执行debounce这个函数 执行debouce就会初始化 let timer 下面的clearTimeout就没有办法清除定时器

解决办法: 直接把这个timer给this 每次执行的时候都不会初始化timer
当然 比较笨的办法就是先把debouce函数的返回函数缓存下来 点击的时候才执行

let d = debounce(function () {
console.log('事件函数')
}, 1000)

function btnclick() {
d()
}

  function debounce(fn, delay) {
    // 返回一个函数,这个函数会在一个时间区间结束后的 delay 毫秒时执行 fn 函数
    return function () {
      // 保存函数调用时的上下文和参数,传递给 fn
      let context = this
      let args = arguments
      // 每次这个返回的函数被调用,就清除定时器,以保证不执行 fn
      clearTimeout(this.timer)
      // 当返回的函数被最后一次调用后(也就是用户停止了某个连续的操作),
      // 再过 delay 毫秒就执行 fn
      this.timer = setTimeout(function () {
        fn.apply(context, args)
      }, delay)
    }
  }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容