封装防抖函数和节流函数

前言

我们知道, 在我们做项目的时候有时候会用到防抖和节流,比如们在提交表单的时候,或者点击某个按钮获取数据的时候,为了防止点击的频率过快导致重复的请求,我们会使用防抖来处理,在比如有时候在使用搜索的时候频繁改变输入内容,我们想要隔一段时间内获取一次,就要使用节流

共用代码:

function subnum() {
  console.log(1);
}
var btn = document.querySelector(".btn");
console.log(btn);
btn.addEventListener("click", debounce(subnum, 1000), false)

防抖函数的实现 🐤🐤

我们首先实现一个简易版的

//封装防抖函数的实现
function debounce(fn, time) {
  var t = null;
  //   这里其实利用了闭包的原理,可以保存变量
  return function () {
    var _this = this;
    var args = arguments;
    // 清除上次的定时器
    if (t) {
      clearTimeout(t);
    }
      t = setTimeout(function () {
        fn.apply(_this, args);
      }, time);
  };
}
  1. 首先我们先讲解一下防抖函数的核心原理:在点击的事件触发之后,首先清除上次的定时器,如果是第一次点击那就进行下一步,设置定时器,此时达到了延时的目的,如果在定时器期间有触发了点击事件,那么此时就会清除上次的定时器(此时定时器中的回调函数没有执行)直到不在重复点击的时候才会最终触发定时器中的回调函数,并且触发fn函数。这就达到了防抖的目的。
  1. 但是目前这个防抖函数还是有就局限性,就是当第一次点击的时候,还是会延时触发,这样就会在某些场景下不满足需求,比如我们想要在第一次点击的时候立即获取,但是如果重复点击的话还是执行最后一次点击,这种情况就不满足。因此我们要对这个防抖函数进行改造,使其功能更加强大

完善防抖函数✌️✌️

​
function debounce(fn, time, triggleNow) {
  var t = null;
  //   这里其实利用了闭包的原理,可以保存变量
  return function () {
    var _this = this;
    var args = arguments;
    // 清除上次的定时器
    if (t) {
      clearTimeout(t);
    }
    // 如果是true表明第一次点击时立即执行函数
    if (triggleNow) {
      var exec = !t;
      if (exec) {
        fn.apply(_this, args);
      }
      t = setTimeout(function () {
        t = null;
      }, time);
    } else {
      t = setTimeout(function () {
        fn.apply(_this, args);
      }, time);
    }
  };
}
​
  1. 首先这次显而易见的是我们函数设计上多设计了一个形参,这个形参的目的就是控制是否要再第一次点击的时候立即执行函数
  2. 这个功能的实现原理:首先如果triggleNow为true时,会进入下面的分支判断中,此时由于时第一次点击t的值为null,那么!t即为true,即exec为true,就会进入下面的判断中,执行fn函数,然后在执行定时器中的回调函数(前提是没有重复点击),否则此时定时器中的回调还是不会执行,当定时器中的回调函数执行之后t被赋值为null。这样就实现了第一次点击的时候立即执行

使用场景:

比如我们此时要进行ajax请求,那么我们就需要进行防抖处理,并且在第一次点击的时候立即进行数据的请求

封装防抖函数和节流函数

可以发现我们在点击的时候只有第一次会触发,多次点击也只会触发一次

当然有时候我们是需要第一次也延时获取的,比如一下场景:当我们在搜索框输入内容的时候,我们不想在第一次输入内容的时候就请求数据,这个时候我们就需要将triggleNow设置为fasle。然后当停止输入一段时间之后才会请求数据

节流函数的实现🎈🎈

节流函数和防抖函数类似,但是略有不同,防抖函数是在规定的时间内,不管你点击多少下只会触发最后一次,节流则是在一段时间内执行一次。

直接贴上代码

// 节流函数
function throttle(fn, time) {
  var begin = new Date().getTime();
  console.log(begin);
  return function () {
    clearTimeout(t);
    var _this = this;
    var args = arguments;
    var cur = new Date().getTime();
    if (cur - begin > time) {
      fn.apply(_this, args);
    }
    begin = cur;
  };
}
​

在网上查阅资料,发现很多人的节流函数是这么写的。这样做确实也可以,但是如果我频繁的点击,并且在设置的一段时间内,那么如果我点击的足够快造成的结果就是这个函数一次也不会调用,我认为这有些不合适。于是我进行了一些改造

function throttle(fn, time) {
  var t = null;
  var begin = new Date().getTime();
  console.log(begin);
  return function () {
    clearTimeout(t);
    var _this = this;
    var args = arguments;
    var cur = new Date().getTime();
    if (cur - begin > time) {
      fn.apply(_this, args);
    } else {
      t = setTimeout(function () {
        fn.apply(_this, args);
      }, time);
    }
    begin = cur;
  };
}
​

这样改进后的如果在时间间隔内调用,那么会执行函数,如果频繁的点击,那么也会执行一次函数,这样就实现的功能比较全面

那么我就说一下实现的思路:

  1. 首先创建一个t变量为null,然后在页面渲染的时候就会调用throttle函数,创建begin变量,然后在点击事件触发的时候,先清除之前的定时器,然后获取点击的时候的当前时间戳,然后用当前的时间戳去减去之间的时间戳如果时间大于time那么此时就可以执行函数
  2. 否则如果时间间隔小于time的时候,当不在点击的时候就会执行一次,注意让最后执行完成之后,会将cur赋值给begin,作为下次的开始的时间戳。

使用场景:其实节流函数和防抖函数的使用场景会有冲突,具体的使用情况要看业务的需求,节流函数也可以使用在比如ajax的请求上面,或者在拖动滚动条需要监听滚动条的时候,就也可以使用节流函数

总结 🤠🤠

防抖函数和节流函数我们能经常遇到,无论是在面试过程中,还是在实际的项目开发中,这就要求我们必须掌握这部分知识,并且这两个函数输入功能型函数,实现封装之后,复用性比较高。因此掌握还是非常有必要的

原文链接:https://juejin.cn/post/7235083283133644858 作者:前端随想

(0)
上一篇 2023年5月21日 上午11:02
下一篇 2023年5月21日 上午11:13

相关推荐

发表回复

登录后才能评论