JavaScript-防抖

lxf2023-03-19 20:23:01

持续创作,加速成长!这是我参与「AdminJS日新计划 · 10 月更文挑战」的第30天,点击查看活动详情

前言

说到防抖,很多人会不明白是什么意思?举个简单的例子,在游戏里,防抖就类似王者荣耀里的回城,被打断了就得重新回城;在代码里,防抖就是触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。我们如何实现防抖呢?

防抖

防抖主要是围绕触发事件setTimeoutclearTimeout这三个功能来进行防抖操作的

假设为了防止用户多次点击操作按钮,因此我们需要进行防抖操作,前面说到触发事件,因此我们用到addEventListener,按钮被点击后就会触发addEventListener里面的函数,我们需要延迟执行addEventListener里面的函数,就需要用到setTimeout了,仅仅延迟执行还不够,用户继续点击按钮的话需要清除延时,还得加入clearTimeout

JavaScript-防抖

举个简单的案例演示,新建一个按钮,在js里获取这个按钮,创建一个函数,这个函数表示事件触发要执行的任务,最后给按钮添加事件监听,点击一下按钮就会有正常的监听效果

<button>点击</button>
<script>
    const button=document.querySelector('button')

    function btnClick(){
      console.log('点击');
    }

    button.addEventListener('click',btnClick)
</script>

接下来要进行防抖设置了,创建一个防抖函数并把事件触发执行的任务设置为这个防抖函数,明显要在防抖函数里执行原来的任务,这就需要为防抖函数设置一个参数,并且执行这个参数

function debounce(func){
  func()
}
button.addEventListener('click',debounce(btnClick))

JavaScript-防抖

但是这样在定义监听函数的时候就直接执行了函数,这是防抖的第一个难点,为了解决我们需要用高级函数,就是在函数里返回函数,刷新后就没有错误了

function debounce(func){
  return function(){
    func()
  }
}

接下来就可以设置延时了,在返回函数里加一个setTimeout,在里面执行btnClick这个函数,同时也在防抖函数里新增第二个参数,作为延时的事件,延时效果就出来了

function debounce(func,delay){
  return function(){
    setTimeout(() => {
      func()
    }, delay);
  }
}

button.addEventListener('click',debounce(btnClick,1000))

有延时就有清除延时,在定义监听时间的时候就定义一个变量,所有独立的执行函数都能访问到这个变量,而且这个变量只创建了一次,只需要不断给变量赋值进行延时,然后在返回函数里清除延时

function debounce(func,delay){
  let timer
  return function(){
    clearTimeout(timer)
    timer=setTimeout(() => {
      func()
    }, delay);
  }
}

JavaScript-防抖

连续点击多次控制台也只显示一条信息,看似防抖函数实现了,但是还有一个地方被我们忽略了

function btnClick(){
  console.log('点击');
  console.log(this);
}

JavaScript-防抖

在事件触发要执行的任务的函数里打印this,看看this的指向,this的指向应该是指向button的但是控制台显示指向了window。因为回调的原因,运行时已经在window下了,所以我们要在延时之前把this保存下来,此时this指向按钮,在延时中用call来绑定这个this给事件触发要执行的任务的函数,最后控制台打印正确

function debounce(func,delay){
  let timer
  return function(){
    let context=this
    clearTimeout(timer)
    timer=setTimeout(() => {
      func.call(context)
    }, delay);
  }
}

JavaScript-防抖