JavaScript高级学习:事件的防抖和节流02——详解防抖

提示:
本文为JavaScript栏目:JavaScript高级学习:事件的防抖和节流02——详解防抖


防抖

防抖的思路

如果在delay时间内没有再次触发滚动事件,那么就执行函数
如果在delay时间内再次触发滚动事件,那么当前的计时取消,重新开始计时

简单来说就是把事件的触发当做成一个技能。在技能释放的时候需要delay时间的蓄力,而且不能被打断,如果被打断则会重新开始蓄力。

初步实现

既然前面都提到了计时,那实现的关键就在于setTimeout这个函数,由于还需要一个变量来保存计时,考虑维护全局纯净,可以借助闭包来实现

<script>
    let app=document.getElementById("app");
   function fun(ev) {
        app.innerHTML = parseInt(app.innerHTML)+1;
    }
    function debounce(fun, delay) {
        let timeOut;
        return function() {
            console.log(timeOut)
            if (timeOut) clearTimeout(timeOut);
            timeOut = setTimeout(function() {
                fun.apply()
            }, delay);
        }
    }
    app.onmousemove=debounce(fun,100)
</script>

效果:
在这里插入图片描述

解决指针问题和event对象

利用箭头函数,解决this指向问题

<script>
    let app = document.getElementById("app");

    function fun(ev) {
        app.innerHTML = parseInt(app.innerHTML) + 1;
    }

    function debounce(fun, delay) {
        let timeOut;
        return function() {
            let args = arguments;
            if (timeOut) clearTimeout(timeOut);
            timeOut = setTimeout(()=> {
                fun.call(...args);
            }, delay)
        }
    }
    app.onmousemove = debounce(fun, 100)
</script>

这里基本就实现了防抖,下定义:
防抖的含义就是让某个时间期限(如上面的100毫秒)内,事件处理函数只执行一次。

大招后摇

我们实现防抖的方式实在计时结束后执行函数,可是很多时候,也会要求我们立刻触发事件执行,等待一些事件后次才能继续执行这个事件。说白了,就相当于我们的技能有后摇,用完技能要等一会才能触发事件。

我们的解决方法是传递一个参数进去要求我们立刻执行,此时,函数的执行不包含在计时器内部,而是执行玩函数后,给定一个计时器用于作为大招后摇。

<script>
    let app = document.getElementById("app");

    function fun(ev) {
        app.innerHTML = parseInt(app.innerHTML) + 1;
    }

    function debounce(fun, delay, immediate) {
        let timeOut;/*闭包返回定时器*/
        return function() {
            that = this;    /*解决指针问题*/
            args = arguments;   /*解决event时间问题*/
            if (timeOut) clearTimeout(timeOut);/*清除正在运行的计时器*/
            if (immediate) {
                /*判断是否立即执行*/
                let playNow = !timeOut;/*false*/
                timeOut = setTimeout(function() {
                    timeOut = null;
                }, delay)   /*添加一个计时,不进行直接操作*/
                if (playNow) {
                    console.log(playNow)
                    fun.call(this, ...args)
                }
            } else {
                timeOut = setTimeout(function() {
                    fun.call(that, ...args);
                }, delay)
            }
        }
    }

    app.onmousemove = debounce(fun, 1000,true)
</script>

补充:返回值和取消操作

如果我们执行的事件是拥有返回值的,且必要的情况下,我们需要直接取消掉本次计时器,开始新的一轮。

<script>
function debounce(func, wait, immediately) {
  let timer /*闭包返回计时器*/
  let debounced = function (...args) { /*闭包返回防抖器*/
    let result  /*执行函数的返回值*/
    // 清除闹钟后,闹钟还是存在的
    if (timer) clearTimeout(timer) /*进入该分支语句,说明当前正在一个计时过程中,并且又触发了相同事件。所以要取消当前的计时,重新开始计时*/
    if (immediately) {  /*判断是否立即执行*//*理解为技能后摇*/
      let called = !timer   /*false*/
      timer = setTimeout(() => {
        timer = null
      }, wait)/*添加一个计时,不进行直接操作*/

      if (called) {
        result = func.apply(this, args) /*包装成返回值*/
      }
    } else {/*理解为技能前摇蓄力*/
      timer = setTimeout(() => {
        func.apply(this, args)
      }, wait)
    }
    return result
  }
  debounced.cancel = function () {
    clearTimeout(timer)
    timer = null
  }/*触发取消操作,直接取消本次计时器 ,开启新的一轮*/
  return debounced
}
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值