【JS】防抖和节流

是什么

在这里插入图片描述作用:
(页面性能优化)本质上是优化高频率执行代码的一种手段。
防止频繁调用函数带来的性能损耗和卡顿,可以通过防抖和节流来限制函数的执行次数,节省计算资源。
定义:
防抖:当连续触发事件后,在n秒内只执行最后一次;如果在n秒内被重复触发,就会重新计时。
节流:当事件频繁触发时,在n秒内只能执行一次。
一个经典的比喻:
想象每天上班大厦底下的电梯。把电梯完成一次运送,类比为一次函数的执行和响应
假设电梯有两种运行策略 debounce 和 throttle,超时设定为15秒,不考虑容量限制
电梯第一个人进来后,等待15秒。如果过程中又有人进来,15秒等待重新计时,直到15秒后开始运送,这是防抖。
电梯第一个人进来后,15秒后准时运送一次,这是节流。
第三方库
lodash/underscore

防抖(debounce函数)

案例:
用户在搜索时,不要每输入一个字符就发送请求,比如在500ms之内,用户连续输入了,要等他停下来没有再输入东西,等500ms之后再发送请求;如果在还剩100ms又重新输入了,就需要把前面的事件和时间清空,直到输完之后不再输入,然后再重新等500ms再执行。(如果有发生新的事件就需要继续等待)(每次触发事件时都取消之前的延时调用方法)
应用场景:
①输入框中频繁输入内容,搜索或者提交信息;搜索框联想;
②用户缩放浏览器resize事件;
③按钮事件;
④回城技能(回城需要十秒,等你回了城出来再次回城或者是被对面打断回城了,还是需要十秒钟)
代码实现:
实现方式:每次触发事件时设置一个延迟调用方法,并且取消之前的延时调用方法
方式一:使用第三方库

<body>
  <script src="https://cdn.jsdelivr.net/npm/underscore@1.13.4/underscore-umd-min.js"></script>
  <input type="text">
  <script>
    const inputEl = document.querySelector("input")
    let counter = 0;
    const inputChange = function () {
      console.log(`发送了第${++counter}次网络请求`)
    }

    //防抖处理
    inputEl.oninput = _.debounce(inputChange, 2000)
    //节流处理
    //inputEl.oninput = _.throttle(inputChange, 2000)
  </script>
</body>

方式二:手写函数 oninput绑定

<input type="text">
<script>
  //const常量,值不可再修改、let变量,值可以修改,有块级作用域
  const inputEl = document.querySelector("input")
  let counter = 0;
  const inputChange = function (e) {
    console.log(`发送了第${++counter}次网络请求`, this, e.target.value)
  }

  // oninput事件在元素值发生变化时立即触发
  // 在输入框输入内容的时候立即触发防抖函数debounce,并且传入要使用防抖的函数和延迟时间
  inputEl.oninput = debounce(inputChange, 1000)

  //封装防抖函数
  //参数:fn是需要防抖的函数;delay是延迟时间
  function debounce(fn, delay) {
    //此时打印的this指向window
    console.log(this, "debounce")
    //用来存放定时器的返回值;记录有没有定时器
    let timer = null
    //利用闭包,确保我们声明的变量timer不会被销毁(return里面有引用timer所以不会被销毁)
    //这个函数本身又返回一个新的函数(如果这里return的是箭头函数,则没有this,会向上查找this,找到window)
    //...args不定参数,表示不确定参数个数
    return function (...args) {
      //每当用户输入的时候把前一个setTimeout清除掉(调用一次防抖函数 就清除上一次定时器)
      clearTimeout(timer)
      //然后又创建一个新的setTimeout, 这样就能保证interval间隔内如果时间持续触发,就不会执行fn函数
      //setTimeout两个参数:要执行的函数(这里又必须是箭头函数,不然this指向window)、等待时间
      timer = setTimeout(() => {
        //将this指向改为input
        fn.apply(this, args)
      }, delay)
    }
  }
</script>

方式二:手写函数 addEventListener绑定

<input type="text">
<script>
  /***此时文本框每次输入都会触发input事件***/
  //使用普通函数代码如下 使用普通函数this指向input(DOM对象)
  /* document.querySelector("input").addEventListener("input", function (e) {
    console.log(this, e.target.value)
  })*/
  //使用箭头函数代码如下 使用箭头函数this指向window
  /* document.querySelector("input").addEventListener("input", (e) => {
    console.log(this, e.target.value)
  })*/

  /***使用防抖函数***/
  document.querySelector("input").addEventListener(
    "input",
    debounce(function (e) {
      console.log(this, e.target.value)
    }, 1000)
  )
  function debounce(fn, delay) {
    let timer = null;
    return function(...args){
      clearTimeout(timer);
      timer = setTimeout(() => {
        fn.apply(this, args);
      }, delay)
    }
  }
</script>

节流(throttle函数)

节流过程:如果这个事件会被频繁触发,那么节流函数会按照一定的频率来执行函数。不管这个中间有多少次触发这个事件,执行函数的频率总是固定的。
应用场景:
①监听页面的scroll滚动事件(触底加载更多/滚动加载更多事件);
②频繁点击按钮click事件;
③鼠标移动事件;
④游戏中的一些设计(闪现技能,使用过一次后在这90秒内是无法使用的,但是过了90s又可以再次使用)。
方式一:使用第三方库
方式二:手写函数 oninput绑定
思路:利用开关思想,每次经过3秒执行一次

<input type="text">
<script>
  const inputEl = document.querySelector("input")
  let counter = 0;
  const inputChange = function (e) {
    console.log(`发送了第${++counter}次网络请求`, this, e.target.value)
  }

  // oninput事件在元素值发生变化时立即触发
  // 在输入框输入内容的时候立即触发防抖函数throttle,并且传入要使用防抖的函数和延迟时间
  inputEl.oninput = throttle(inputChange, 3000)

  //封装节流函数
  //不管在3秒内发送多少次请求,在规定时间内都只执行一次
  function throttle(fn, delay) {
    let flag = true;
    return function (...args) {
      if (!flag) return;
      flag = false;
      setTimeout(() => {
        fn.apply(this, args);
        flag = true;
      }, delay)
    }
  }
</script>

区别

  • 相同点:
    都可以通过使用 setTimeout 实现;
    目的都是降低回调执行频率,节省计算资源;
  • 不同点:
    防抖关注一定时间连续触发的事件,只在最后执行一次,而节流一段时间内只执行一次;
    防抖是将多次执行变为最后一次执行,节流是将多次执行变为每隔一段时间执行;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值