如何实现函数节流和函数防抖?

函数节流

函数节流从现象来看首次执行事件函数后间隔一段时间后再次执行该事件函数,从而将频繁的触发导致的事件函数频繁执行这一频率给降低。

如下图频率的比较
在这里插入图片描述
从图上看出,未进行节流处理的事件回调函数,会因为频繁的触发导致事件回调函数频繁的执行,如果是含有请求的事件回调函数,那么势必对服务器造成压力,如果是操作dom元素也会对浏览器的渲染产生压力。

应用场景

比如:onresize,onmousemove,onscroll,oninput等事件中会用到节流函数;

函数节流实现

function throttle(callback, delay) {
      let preTime = 0;
      return function (e) {
        let currTime = Date.now();
        if (currTime - preTime > delay) {
          callback.call(this, e);
          preTime = Date.now();
        }
      }
    }

那么该实现方式的思路:因为事件回调函数是每间隔一段事件后再次执行的,所以我们需要传递一个delay参数表示间隔时间,首次执行回调函数之后需要间隔delay的时长,因此需要记录当前的时间(毫秒),利用第二次进入的时间和第一次保存的时间进行比较是否大于delay设置的间隔时间,如果大于我们才执行时间回调函数,因为首次需要执行时间回调函数,所以初次我们将preTime设置为0,这样第一次肯定满足我们的if条件。
另外,还需要注意的是,我们的回调函数不能直接调用,而需要通过call来改变this指向,让我们的事件回调函数的this重新指向事件源,即被触发的元素。

代码测试

 <button class="throttle">函数节流</button>
  <script>
   var oThrottle = document.querySelector('.throttle');
   oThrottle.addEventListener('click', throttle(throttleHandler,2000), false);//为了效果明显将间隔时间设置为2000ms
    function throttleHandler(e) {
      console.log('函数节流', e, this)
    }
    function throttle(callback, delay) {
      let preTime = 0;
      return function (e) {
        let currTime = Date.now();
        if (currTime - preTime > delay) {
          callback.call(this, e);
          preTime = Date.now();
        }
      }
    }
  </scrpipt>

在这里插入图片描述
可看出每个2s才再次执行回调函数。达到了节流效果了。

函数防抖

函数防抖从效果上来说,事件频繁触发结束,一段时间后才执行事件回调函数且执行一次,再此之前不执行事件回调函数。

如下图频率的比较
在这里插入图片描述

该图显示,首次事件回调函数不会执行,在间隔一定时间后才会执行,且执行一次。

应用场景

典型案例是,远端模糊搜索框,注册时用户名实时是否注册等。

函数防抖实现

 function debounce(callback, delay) {
      return function (e) {
        if (callback.hasOwnProperty('timerId')) {
          clearTimeout(callback.timerId)
        }
        callback.timerId = setTimeout(() => {
          callback.call(this, e)
          delete callback.timerId
        }, delay)
      }
    }

该实现方式利用到了setTimeout定时器,实现思路,其实需要从效果上来理解。当我们频繁的触发事件,例如频繁的点击按钮,那么当你一直再点击按钮的时候是不会执行事件回调函数的,那么怎么做到这一点呢,在函数防抖的实现中 是通过判断是否存在timerId标识,如果存在的话我们就立刻清除该定时器那么事件回调函数就不会执行了,因此当我们一直点就按钮这段时间是不会有任何事件回调的,当点击结束超过delay设置的事件时这时候才会执行setTimeout中的事件回调函数。

  • 将timerId挂载到callback函数对象上方便我们拿,你也可以不放在callback上面
  • 使用箭头函数是为了this的指向不被改变

代码测试

  <button class="debounce">函数防抖</button>
  <script>
    var oDebounce = document.querySelector('.debounce');
    oDebounce.addEventListener('click', debounce(debounceHandler,1000), false);
    function debounceHandler(e) {
      console.log('函数防抖', e, this)
    }
    function debounce(callback, delay) {
      return function (e) {
         if (callback.hasOwnProperty('timerId')) {
          clearTimeout(callback.timerId)
        }
        callback.timerId = setTimeout(() => {
          callback.call(this, e)
          delete callback.timerId
        }, delay)
      }
    }

在这里插入图片描述
上图展示了函数防抖的实际效果。为了效果明显,我设置的时间间隔为1000ms,正常开发中一般不会设置这么长。

路漫漫其修远兮


版权声明:本文为weixin_43213137原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。