防抖和节流

防抖和节流

一. 防抖

###1. 概念

防抖是指:一个事件被触发的时候,里边的函数不会立即被触发,而是会等待一段时间再触发。

  • 举个例子:游戏中的回城就可以认为是防抖,在回城的读秒过程中,如果再次执行回城操作,那么会重新进行读秒,只有整个读秒过程都没有再次执行回城操作,那么等到读秒结束才能成功回城。

###2. 防抖使用场景:

​ input输入框频繁输入内容时。

​ 频繁点击按钮,触发某个事件。

​ 监听浏览器滚动或鼠标滚动。

3. 防抖讲解

​ 未使用防抖时:

var aa = document.getElementById('ipt')
    // 监听键盘按下事件
    document.addEventListener('keyup',function(){
      console.log(aa.value)
    })

​ 效果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hcjuihvN-1653654541063)(C:\Users\17679\AppData\Roaming\Typora\typora-user-images\image-20220423164741522.png)]

​ 加上防抖时:

	var aa = document.getElementById('ipt')
    // 判断当前是否有在有定时器
    let t = null
    // 监听键盘按下事件
    document.addEventListener('keyup',function(){
      // 判断当前监听到的事件是否在防抖时间里
      if(t != null){
        // 不为空则说明上一次触发事件还在时间内,则清除掉当前已记录的时间,重新开始计时
        clearTimeout(t)
      }
      t = setTimeout(function(){
        // 业务逻辑
        console.log(aa.value)
      },1000)
    })

​ 效果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GTxh62IT-1653654541065)(C:\Users\17679\AppData\Roaming\Typora\typora-user-images\image-20220423165653738.png)]

​ 如此做有一个弊端,也就是当前的业务逻辑和防抖处理交织在一起,且还多了个全局变量 t,一旦业务逻辑多了起来,可读性会非常差,不利于维护。可以将防抖处理封装起来,以求和业务逻辑分开来。

    var aa = document.getElementById('ipt')
    
    // 使用debounce防抖函数去约束逻辑业务,由于逻辑业务是一个function函数形式的
    // 那么debounce的返回值就应该是一个函数
    document.addEventListener('keyup',debounce(function(){
      // 是真正的业务逻辑
      console.log(aa.value)
    },1000))


    // 这个fn是为了执行业务逻辑函数
    function debounce(fn,delay){
	  // 判断当前是否有在有定时器
      let t = null
      // 返回一个函数 (那么debounce的返回值就应该是一个函数)
      return function() {
        // 判断当前监听到的事件是否在防抖时间里
        if(t != null){
          // 不为空则说明上一次触发事件还在时间内,则清除掉当前已记录的时间,重新开始计时
          clearTimeout(t)
        }
        t = setTimeout(function(){
          // 业务逻辑函数
          fn()
        },delay)
      }
    }

​ 如此,可以实现防抖的封装。但是又产生了一个问题,如果采用 this.value 的方式进行,打印结果是undefined。因为匿名函数的this指向window,而window中是没有value的。可以采用call方法来改变this的指向。

二. 节流

###1. 概念

​ 控制执行次数。

  • 节流是指当事件触发时,会执行这个事件的响应函数。
  • 但是该事件如果被频繁触发,那么节流函数会按照一定的频率来执行函数
  • 举个例子:节流类似于技能cd,不管你按了多少次,必须等到cd结束后才能释放技能。也就是说在如果在cd时间段,不管你触发了几次事件,只会执行一次。只有当下一次cd转换,才会再次执行。

2. 节流应用场景

​ 比如对于一个Button短时间内进行多次点击,可能没有必要触发多次handler,这时候就可以对click的响应函数进行节流处理。

​ 或者一个使用键盘控制的飞机大战的游戏,子弹的射出速度是有限制的,不管你在短时间内触发多少次发射按键,永远只会有一枚子弹被发射。

​ 再或者是在实现无限滚动时,需要去监测内容底部是否已经接近window底部,如果是的话就需要去请求新的内容。

###3. 节流讲解

    // 设置一个标志,若为true,则触发滚轮
    let flag = true
    window.onscroll = function() {
      if(flag) {
        setTimeout(function(){
          console.log('触发了滚轮事件')
        },1000)
      }
      // 事件触发后,立刻将flag设为false
      flag = false
    }

​ 以上代码可以实现节流,但只能实现一次,下面的代码利用了setTimeout是异步执行的方式。完整实现节流。

    // 设置一个标志,若为true,则触发滚轮
    let flag = true
    window.onscroll = function() {
      if(flag) {
        setTimeout(function(){
          console.log('触发了滚轮事件')
          // 当触发事件并开启计时后,将flag设为true
          flag = true
        },1000)
      }
      // 事件触发后,立刻将flag设为false
      flag = false
    }

​ 以下为封装:

      // 设置一个标志,若为true,则触发滚轮
      window.onscroll = throttle(function () {
        console.log('触发了滚轮事件')
      }, 1000)

      // 封装
      function throttle(fn, delay) {
        let flag = true
        return function () {
          if (flag) {
            setTimeout(function () {
              fn()
              // 当触发事件并开启计时后,将flag设为true
              flag = true
            }, delay)
          }
          // 事件触发后,立刻将flag设为false
          flag = false
        }
      }

/ 当触发事件并开启计时后,将flag设为true
flag = true
}, delay)
}
// 事件触发后,立刻将flag设为false
flag = false
}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值