防抖和节流的实现与区别(vue2、vue3写法)

防抖:不断触发一个方法,在规定时间内只让最后一次有效访问,如果这期间又再次触发,则重新计时

 应用场景:
1. 登录、发短信、搜索框输入等按钮避免用户点击太快,以致于发送了多次请求,需要防抖。

2. 调整浏览器窗口大小时,resize 次数过于频繁,造成计算过多,此时需要一次到位,就用到了防抖。

3. 文本编辑器实时保存,当无任何更改操作一秒后进行保存。

 代码实现要点:设置一个定时器,通过闭包,抓住定时器变量,控制定时器的添加和删除

 vue3写法

<el-input
  v-model="str"
  placeholder="请输入"
  @keyup="testDebounce"
  style="width: 300px"
  clearable
  />

  <script>
    const testDebounce=debounce((e)=>{
      console.log(e.target.value)
    },2000)

    //防抖实现
    function debounce(fn,delay){   //传入所要防抖的方法或者回调与延迟时间
      let timer = null
      //借助闭包,使得变量timer不被回收
      // 将debounce处理结果当作函数返回
      return function() {
        //保存当前环境下的实例对象,this即为引入该方法的那个组件实例对象
        let th = this;
        //保存传入参数
        let args = arguments;
        //第一次timer为null,跳过该判断,执行setTimeout()
        if(timer){
          //之后如果timer存在,则把上一次的销毁,也就是setTimeout(),则里面的函数执行也会抛弃
          clearTimeout(timer)
        }
        timer = setTimeout(()=>{
          //apply(),改变this指向,指向正在操作的组件实例,传入参数
          fn.apply(th, args)
        }, delay)
      }
    }
  </script>
    //由于使用闭包,使得timer不被回收,在A组件中每次调用该方法时会去判断timer是否存在,如果存在,
    //表示上一次输入在等待执行fn(),期间如果继续输入,且在1s内,则会把上一次未执行的
    //(setTimeout中的)fn()销毁,重新定时1s,以此来达到输入结束过1s才执行fn(),即触发事件或者发送
    //请求。

vue2写法

<template>

</template>

<script>
  /* 防抖函数 */
  let debounce = function (callback, delay) {
    // 使用闭包的外部变量来定义定时器
    let timer;
    return function () {
      // 判断是否已经存在定时任务
      if (timer) {
        /*如果已有定时任务就将已有任务清除,再重新生成新的定时任务*/
        clearTimeout(timer)
      }
      // 生成定时任务并赋值给timer
      timer = setTimeout(() => {
        callback.call(this)
      }, delay)
    }
  }
  let ajax = function () {
    //利用定时器来模拟异步操作
    setTimeout(() => {
      // 使用日志输出来模拟ajax请求
      console.log("发起ajax请求" + ",时间戳为:" + new Date());
    }, 1000)
  }
  // 给输入框对象绑定键盘输入事件
  input.oninput = debounce(ajax, 1000)
</script>

节流:单位时间内,只能触发一次(首次)

用场景:

1. 滚动scroll 事件,每隔一秒计算一次位置信息。

vue3写法

<template>
  <div style="width: 100%; height: 2000px; background-color: pink">滚动事件</div>
</template>

<script>
  const throttle = (fn, delay = 2000) => {
    let flag = true
    return function() {
      let th = this;
      let args = arguments;
      if(!flag){
        //未超过时间间隔,flag无效,不执行fn
        return false 
      }
      fn.apply(th, args)
      flag = false    //在时间间隔内把状态位flag设为无效(false)
      setTimeout(() => {
        flag = true   //超过时间间隔把状态位flag设为有效(true)
      }, delay)
    }
  };

  const better_scroll = throttle(e => {
    console.log('触发了滚动事件' + e.target.documentElement.scrollTop);
  },3000);

  onMounted(() => {
    document.addEventListener('scroll', better_scroll);
  });


export function _throttle(fn, interval) {
    var last;
    var timer;
    var interval = interval || 200;
    return function () {
        var th = this;
        var args = arguments;
        var now = +new Date();
        if (last && now - last < interval) {
            clearTimeout(timer);
            timer = setTimeout(function () {
                last = now;
                fn.apply(th, args);
            }, interval);
        } else {
            last = now;
            fn.apply(th, args);
        }
    }
}
  
</script>

vue2写法 

<template>

</template>

<script>
  /* 通过判断flag来实现节流 */
  let throttle = function (callback, delay) {
    // 判断依据
    let flag = true
    return function () {
      // 如果flag为false便忽略这次操作
      if (flag) {
        //设定定时器,当任务执行时将flag恢复false,允许下一次的事件触发
        setTimeout(() => {
          callback.call(this)
          flag = true
        }, delay)
      }
      //在定时任务执行之前,flag始终为false
      flag = false
    }
  }
  /* 通过时间来判断 */
  let throttling = function (callback, delay) {
    // 设置一个记录的时间,用以判断是否忽略操作
    let time = 0;
    return function () {
      // 创建当前时间,用以判断是否超过设定好的延迟
      let now = new Date()
      // 如果两次事件触发时间差大于设定好的毫秒数,则触发新的请求
      if (now - time > delay) {
        // 执行回调函数
        callback.call(this)
        // 将记录的时间设置为这一次执行任务的时间
        time = now
      }
    }
  }

  let ajax = function () {
    //利用定时器来模拟异步操作
    setTimeout(() => {
      // 使用日志输出来模拟ajax请求
      console.log("发起ajax请求");
    }, 1000)
  }
  window.onscroll = throttling(ajax, 3000)
</script>

总结

防抖主要是为了解决事件频繁触发的问题,且仅采取频繁触发的最后一次操作。

节流也是为了解决事件频繁触发的问题,且仅采取频繁触发的第一次操作。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值