防抖与节流及其实现

68 阅读2分钟

本质上是优化高频率执行代码的一种手段

如:浏览器的 resizescrollkeypressmousemove 等事件在触发时,会不断地调用绑定在事件上的回调函数,极大地浪费资源,降低前端性能

为了优化体验,需要对这类事件进行调用次数的限制,对此我们就可以采用 防抖(debounce)  和 节流(throttle)  的方式来减少调用频率

防抖

防抖(debounce):不管事件触发频率多高,一定在事件触发n秒后才执行,如果你在一个事件触发的 n 秒内又触发了这个事件,就以新的事件的时间为准,n秒后才执行,总之,触发完事件 n 秒内不再触发事件,n秒后再执行。

有时候我们需要让函数立即执行一次,再等后面事件触发后等待n秒执行,我们给debounce函数一个flag用于标示是否立即执行。

当定时器变量timer为空时,说明是第一次执行,我们立即执行它。

function debounce(event, time, flag) {
        let timer = null;//初始化计时器变量
        return function (...args) {
          clearTimeout(timer);//清除上一个计时器
          if (flag && !timer) {//如果传入了flag且第一次使用立刻触发不用倒计时
            event.apply(this, args);//args将参数作为数组传给event函数
          }
          timer = setTimeout(() => {//倒计时开始,也是防抖的关键
            event.apply(this, args);
          }, time);
        };
      }

测试代码

<body>
    <div
      onclick="deli()"
      style="background-color: pink; height: 1000px; width: 1000px"
    >
      <p>这是一个粉色的 div。</p>
    </div>
    <script>
      var element = document.querySelector("div");
     //防抖实现
											//
      function bigger() {
        element.style.backgroundColor = "red";
        console.log('work');
      } // Cherry
      var deli = debounce(bigger, 600);
    </script>
  </body>

PS:传入flag且第一次触发时会触发两次

节流

节流(throttle):不管事件触发频率多高,只在单位时间内执行一次。

1.时间戳实现(第一次立刻触发)

...args用于接受使用throttle的方法的传参

function throttle(event, time) {
      let pre = 0;
      return function (...args) {
        if (Date.now() - pre > time) {
          pre = Date.now();
          event.apply(this, args);
        }
      }

2.定时器实现(最后一次一定触发)

function throttle(event, time) {
          timer = null;
          return function (...args) {
            if (!timer) {
              timer = setTimeout(() => {
                timer = null;//不添加这一行就无法再次进入if进行倒计时
                event.apply(this.args);
              }, time);
            } 
          };
        }

测试代码:与防抖相同
参考:www.conardli.top/docs/JavaSc…