防抖和节流的定时器写法和时间戳写法详解

防抖和节流

一、防抖

1. 什么是防抖?

防抖指在一段时间内触发一次事件函数,如果单位时间(就是定时器设置的时间)还没有到达,再次触发事件函数的话,那么立刻停止触发上一次的事件,然后直接重新计算间隔时间,只执行最后一次的触发的事件。

2.代码实现
<!DOCTYPE html>
<html lang="en">

<head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
</head>

<body>
      <button>你点吧,我只执行最后一次</button>
      <script>
          function debounce(fn,delay){
            let timer = null
            
            return function(){
                  clearTimeout(timer)
                  timer = setTimeout(()=>{
                       fn.apply(this,arguments)
                       clearTimeout(timer)
                  },delay)
            }
          }


            let btn = document.querySelector('button')
            btn.addEventListener('click',debounce(function(e){
                        console.log('别点了,我只执行一次');
            },300))
      </script>
</body>

</html>
2.1代码解释
  • 上面的代码使用闭包+定时器来实现防抖的。大家如果不懂闭包的话,先去看我的这篇闭包的文章,了解后再来看效果好一点。
  • 首先定义了一个debounce函数,然后在定义了一个timer变量赋值为null,相当于外层函数的私有变量,即局部变量。然后返回一个函数,函数里面保存两个变量timer和delay,然后debounce函数外面的按钮监听事件接收这个返回的函数,只要按钮一直监听点击事件,那么debounce函数空间就不会销毁。然后debounce函数里面的返回函数就叫做闭包函数。
  • 闭包函数里面首先的话是先清除一下定时器,然后再开启定时器,定时器里面的fn.apply(this,arguments),解释一下,就是传进来的这个fn通过apply()方法改变this的指向,然后执行。fn就是 btn.addEventListener('click',debounce(function(e){})中debounce的回调函数:function(e){ console.log('别点了,我只执行一次'); }
    有没有发现我定时器里面用的是es6的箭头函数,为什么我要箭头函数?
  • 因为如果我用普通函数的话,那么定时器里面的this指向的是window,但是我们不想要它指向window,我们要让它指向事件源buttton,所以我要使用箭头函数。箭头函数本身是没有this的,它里面的this指向的是他所在的环境: return function(){},而这个函数是由button事件源执行,所以箭头里面的this指向的是事件源button。
3.使用场景
  • 一般用于点击事件,向服务器发送请求。
  • input的输入自动保存事件。
4.作用

防抖的作用是避免事件重复触发。
比如点击按钮发送请求,如果不做防抖的话,用户不知道的话,就一直点击,那么就一直发送请求,那服务器不得崩掉。做了防抖的话,即使点了无数次,不好意思,他只执行一次,只发一次请求,性能那不得杠杠的。

二、节流

1. 什么是节流?

在一段时间内触发一次事件函数,如果前一次触发的事件函数还没有执行,再次触发事件的话就不会做任何操作,在单位时间内触发多次,只会执行第一次触发的事件。

2.上代码

2.1菜鸟级别代码
2.1.1定时器写法
<!DOCTYPE html>
<html lang="en">

<head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
</head>

<body>
      <button>我要抢票!</button>
      <script>

       function throttle(fn,delay){
            let timer=null
            return function (){
                  if(!timer){
                        timer = setTimeout(()=>{
                           fn.apply(this,arguments)
                           timer=null
                        },delay)
                  }
            }
       }
            let btn = document.querySelector('button')
            btn.addEventListener('click',throttle(function (){
                  console.log('别点了,点一次就行了,点再多也没用,在规定的一段时间内我只执行一次!');
            },2000))
      </script>
</body>

</html>
2.1.2时间戳写法

上代码!

<!DOCTYPE html>
<html lang="en">

<head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
</head>

<body>
      <button>我要抢票!</button>
      <script>
            function throttle(fn, delay) {
                  let preTime = new Date()
                  return function () {
                        let nowTime = new Date()
                        console.log(nowTime);
                        if ((nowTime - preTime) > delay) {
                              fn.apply(this, arguments)
                              preTime = nowTime
                        }
                  }
            }

            let btn = document.querySelector('button')
            btn.addEventListener('click', throttle(function () {
                  console.log('别点了,点一次就行了,点再多也没用,在规定的一段时间内我只执行一次!');
            }, 1000))
      </script>
</body>

</html>
  • 上面的时间戳代码,个人觉得这个时间戳写法适合于滚动事件场景,因为只有你不断滚动了才到达规定的时间,事件才会触发,否则,你用在点击事件上的话,你点击一次,事件触发的时间不够规定的时间,这样事件就触发不了,我觉得这个不符合点击事件的节流,更符合滚动事件。
  • 还有一点注意的是:如果你设置的时间较短的时候(比如1~2s),你会发现你第一次等了一会(打开控制台的时间)再触发事件的话,事件会立即执行,这个怎么回事?
  • 新机次挖一直摸你肚子!就是throttle(…)这个函数一开始就执行的,所以let preTime = new Date()会执行,等你第一次触发的话,时间是不是过了一会,所以闭包里面的nowTime减去preTime肯定大于设定的时间(1~2s)。当然,设置的时间长或手速快的话,就不出现上面的现象。
2.2大佬级别的代码
<!DOCTYPE html>
<html lang="en">

<head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
</head>

<body>
      <button>我要抢票!</button>
      <script>
            function throttle(fn, delay) {
                  let flag = true
                  return function () {
                        if (!flag) return //后续不在执行
                        flag = false
                        setTimeout(() => {
                              fn.apply(this, arguments)
                              flag = true
                        }, delay)
                  }
            }

            let btn = document.querySelector('button')
            btn.addEventListener('click', throttle(function () {
                  console.log('别点了,点一次就行了,点再多也没用,在规定的一段时间内我只执行一次!');
            }, 2000))
      </script>
</body>

</html>

3.使用场景

  • 验证码

比如说我们手机发送的验证码,这个就是节流,是不是你发送一次,就要等待一段时间,在这段时间内你是不能再次发送的,即使你按烂了发送按钮。

  • 抢车票

一波操作猛如虎,其实做了太多无用功,啥也不是!。为什么?
人家做了节流,你按烂了抢票按钮,还是只执行第一次触发的事件,到了设定时间,人家会自己执行,这段时间内点的再多,k只执行一次。有没有感觉到自己曾经的行为有点憨憨😎。

4.节流的作用

节流的作用是把频繁触发的事件减少。
比如我们的抢车票,如果不做节流的话,那么我们一点击就会触发,可想而知,抢票的时候用户一个人点了无数次,使用者有那么多,那发送的请求可想而知,开了多少服务器都不好使,直接挂掉。如果做了节流,在规定的时间内,只触发第一次发送的请求,是不是频繁触发的事件减少了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值