JavaScript 中防抖与节流的原理及解析

452 阅读2分钟

本文着中讲述防抖与节流的实现原理。

那么在开始实际代码之前,我们先来说说防抖与节流的本质意思。

1.防抖:在一段时间内,用户不断通过浏览器实现某些功能太过频繁,我们想实现直至用户在一段时间内不再触发某个事件后,我们再执行并实现该功能。

2.节流:在一段时间内,用户通过频繁调用某项功能,而我们只选择一次完成后就不再执行第二次,以达到节省流量的效果。

  <script>
    //防抖
    //获取input标签节点
    var input = document.getElementsByClassName("input")[0]
    //先执行外部函数,由于还未调用内部函数故不输出
    var debounceFunc = debounce(2000)
    //监听键盘的按键抬起事件,回调函数的参数为源事件
    input.addEventListener("keyup",function(e){
      //调用内部函数
      debounceFunc(e.target.value)
    })

    //封装防抖函数
    function debounce(delay){
      let timer
      //在此处定义闭包(也就是在函数中返回一个函数),以达到将函数暴漏出去,并借此将timer这个变量全局化。
      //如果没有闭包,每次进入debounce函数的timer都是最初始的undefined,故无法达到清除定时器的效果。
      return function(value){
        //此时第一次进入时timer是undefined,第二次之后则可以清除外部函数残留的上一次timer计时器,取消执行上一次。
        clearTimeout(timer)
        //timer真正完全执行并渲染将会是最后一次timer
        timer = setTimeout(function(){
          console.log(value)
        },delay)
      }
    }
   
  </script>

2.节流函数演示如下

html

<button id="btn">节流按钮</button>

js

    function runThro(){
      console.log("我是要节流执行的函数")
    }
    document.getElementById("btn").onclick = saveThro(2000,runThro)
    function saveThro(delay,func){
      let timer
      return function(){
        //判断是否为timer是undefined时进入该函数
        if(!timer){
          //此时timer为undefined
          timer = setTimeout(function(){
            //进入定时器,delay期间都在执行这个函数,重复点击是不会触发同时执行的
            func()
            //运行到此处,则想调用的函数已经执行完毕,把timer重新修改为undefined,等待下一个delay期间的函数被调用。
            timer = null
          },delay)
        } 
      }
    }

由此可知: 1.在防抖函数中,被执行的是最后一次调用的函数,而在节流函数中,被执行的是一段事件内第一次被调用的函数。 2.防抖函数之前的所有触发的事件全都被完全取消,最后一次没被取消,所以执行。 3.而节流函数则是第一次才符合判断条件执行,后面调用的所有事件都因timer被占用而无法执行,必须等到第一次调用的函数执行完毕后,timer重新释放,在下一个时间的第一次调用才可以顺利执行,用这样的方式来达到节流的效果。