JS疑难杂症——函数的防抖、节流

今天在学习vue的过程中,老师提到了节流的概念,跟着一顿操作以后虽然达到了效果却不是很明白为什么。在万能的b站上找到了小夏老师的视频,进行了学习,并写下这篇博客作为记录。大家感兴趣的可以去b站上看看原视频函数的防抖和节流 – JS 原生面试题,个人认为思路很清晰,讲的非常好!

防抖和节流

防抖和节流是通过某种方式限制函数执行的次数,减少浏览器在执行非常频繁的操作,如:监听滚动条、改变浏览器框大小、ajax请求等,减少不必要的资源浪费。

1. 防抖

1.1 基本方法

通过setTimeout的方式,在一定时间间隔内,多次触发变成一次触发

var btn = document.getElementById('input')

btn.addEventListener('click', submit, false)

function submit(e) {
   console.log(1)
}

举个例子,我们希望在不断点击的过程中不会一直触发submit函数,我们可以采用防抖的方式

var btn = document.getElementById('input')

btn.addEventListener('click', debounce(submit), false)

function submit(e) {
   console.log(1)
}

//防抖函数
function debounce(fn) {
   //设置一个时间
   var t = null
   return function(){
      //如果t不为空,则让t为空,在时间间隔未到时的函数将不会执行
      if(t){
         cleartTimeout(t)
      }
      //重新触发一个函数,如果再时间间隔未到之间不会触发
      t = setTimeout(function(){
         fun()
      },1000)
   }
}

1.2 防抖中e和this的正确获取

通过这种方式存在着两个问题,一是原本的事件对象该如何获取,二是this指向的问题
我们知道如果在submit函数中打印this和e的话,分别会显示目标元素和触发的事件。那么我们在防抖函数中如何获取正确的e和this呢?e的获取我们可以直接将return的function参数列表添加一个e即可调用

function debounce(fn) {
   var t = null
   return function(e){
      console.log(e) //获取到了事件
      if(t){
         cleartTimeout(t)
      }
      t = setTimeout(function(){
         fun(e)
      },1000)
   }
}

但是我们一般不会这样写,因为我们不确定参数的个数,因为e事件存在于argument[0]中,我们可以想办法通过argument获取事件e。

function debounce(fn) {
   var t = null
   return function(){
      console.log(argument[0]) //获取到了事件
      if(t){
         cleartTimeout(t)
      }
      //注意此处改成箭头函数,因为直接使用函数argument会指向自身的实参列表
      //而不是return的函数的列表
      //apply绑定了this指向了return的函数,并将return的函数的参数列表传给了fun
      t = setTimeout(() => {
         fun.apply(this, argument)
      },1000)
   }
}

这样我们就获取了一个“没有毛病”的函数防抖!

1.3 进一步的优化

但是考虑到有时候我们需要快速的执行第一次函数,并且达到防抖的效果,也就是执行一次函数后的一段时间内函数都不会执行的效果要怎么办呢?

function debounce(fn, timer) {
   var t = null
   return function(){
      //如果t为null,则firstClick为true,则会在后面执行fn
      //如果t不为空,则firstClick为false,则后面不会执行fn
      var firstClick = !t
      if(t){
         cleartTimeout(t)
      }
      if(firstClick){
         fn.apply(this, argument)
      }
      t = setTimeout(() => {
         t = null
      }, timer)
   }
}

在上述函数中,我们第一次点击时t为null,所以firstClick为true,则会在后面执行fn。当第二次点击的时间未到设置的时间间隔时,t不为空,则firstClick为false,则后面不会执行fn。后面如果一直在未到达时间间隔的时候点击会一直循环下去,直到第n次点击的时间和第n-1次点击的时间超过设定的时间间隔,t才会重归为null,firstClick才会为true,以达到后面执行fn的效果。

2. 节流

节流通过减少一段时间触发的频率来达到和防抖一样的效果

function (fn, delay) {
   var begin = 0 
   return function () {
      var cur = new Date().getTime()
      //通过时间差来进行判断
      if(cur - begin > delay){
         fn.apply(this, argument)
         begin = cur
      }
   }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值