防抖和节流

227 阅读2分钟

首先先画一个DIV 用于接下来的展示

    <div
      id="content"
      style="
        height: 150px;
        line-height: 150px;
        text-align: center;
        color: #fff;
        background-color: #ccc;
        font-size: 80px;
      "
    ></div>
      let num = 1;
      let content = document.getElementById("content");
      function count() {
        content.innerHTML = num++;
      }

普通状态

    先来看看鼠标在DIV上面移动并且不进行防抖或者节流的表现,

      content.onmousemove = count;

随着鼠标的移动,数字是不断变大的,如果需要操作大量的DOM 或者请求接口,就不太合适了。

防抖 debounce

     防抖,就是值触发事件后的N秒内函数只会执行一次,如果N秒内又触发了事件,则会重新触发计算函数执行时间,可以用于网页缩放,input输入等等
     防抖可以分为两种情况,一种是鼠标移动立刻执行,还有一种是鼠标移动停下之后才会执行

      function debounce(fn, time, immediate) {
        let canRun = true;
        let timeout;
        if (immediate) {
          return function () {
            if (canRun) {
              canRun = false;
              fn.apply(this, arguments);
            }
            clearTimeout(timeout);
            timeout = setTimeout(() => {
              canRun = true;
            }, time);
          };
        } else {
          return function () {
            if (timeout) {
              clearTimeout(timeout);
            }
            timeout = setTimeout(() => {
              fn.apply(this, arguments);
            }, time);
          };
        }
      }

     fn为执行函数,time为防抖时间,immediate是否立刻执行      先看立即执行的版本,可以看出鼠标移上去的一瞬间数字加1,然后无论怎么移动都不会移动,除非两秒之后在移动

      content.onmousemove = debounce(count, 2000, true);

     然后是延后执行的版本,鼠标移动之后停止两秒之后数字加1,期间无论怎么移动都不会加1

      content.onmousemove = debounce(count, 2000, false);

节流 throttle

    节流,指的是连续触发事件,但是在N秒内只会执行一次     传参和防抖差不多,可以使用定时器或者时间戳,这边使用定时器演示

      function throttle(fn, time, immediate) {
        let canRun = true;
        let timeout;
        if (immediate) {
          return function () {
            if (canRun) {
              canRun = false;
              fn.apply(this.arguments);
              setTimeout(() => {
                canRun = true;
              }, time);
            }
          };
        } else {
          return function () {
            if (canRun) {
              canRun = false;
              setTimeout(() => {
                fn.apply(this.arguments);
                canRun = true;
              }, time);
            }
          };
        }
      }

    首先是立即执行版本,鼠标移动数字立即加1,然后每一秒加1

      content.onmousemove = throttle(count, 1000, true)

    然后是延迟执行版本,鼠标移动在一秒后数字立即加1,然后每一秒末尾加1

      content.onmousemove = throttle(count, 1000, false);