# JS 防抖与节流应用场景和最佳实践

防抖和节流的作用:

  • 都是在高频事件中防止函数被多次调用,是一种性能优化的方案。

区别在于

  • 防抖函数只会在高频事件结束后 n 毫秒调用一次函数
  • 节流函数会在高频事件触发过程当中每隔 n 毫秒调用一次函数。

# 1、应用场景

常见的应用场景都是使用高频事件来调用函数的过程当中

  • 比如:应用于 window 对象的 resize、scroll 事件,拖拽时的 mousemove 事件
  • 文字输入、自动完成的 keyup 事件。

# 2、防抖的应用场景

场景

  • scroll 事件滚动触发事件
  • 搜索框输入查询,如果用户一直在输入中,没有必要不停地调用去请求服务端接口,等用户停止输入的时候,再调用,设置一个合适的时间间隔,有效减轻服务端压力。
  • 表单验证
  • 按钮提交事件。
  • 浏览器窗口缩放,resize 事件(如窗口停止改变大小之后重新计算布局)等。

# 3、节流的应用场景

场景

  • DOM 元素的拖拽功能实现(mousemove)
  • 搜索联想(keyup)
  • 计算鼠标移动的距离(mousemove)
  • Canvas 模拟画板功能(mousemove)
  • 射击游戏的 mousedown/keydown 事件(单位时间只能发射一颗子弹)
  • 监听滚动事件判断是否到页面底部自动加载更多

# 4、封装 防抖函数

TIP

触发高频事件后一段时间(wait)只会执行一次函数,如果指定时间(wait)内高频事件再次被触发,则重新计算时间。

// 防抖函数
function debounce(func, wait) {
  let timeout = null;
  return function () {
    let context = this;
    let args = arguments;
    if (timeout) clearTimeout(timeout);
    timeout = setTimeout(() => {
      func.apply(context, args);
    }, wait);
  };
}

# 5、封装 节流函数

TIP

规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效

// 节流函数
function throttle(func, wait) {
  let timeout = null;
  return function () {
    let context = this;
    let args = arguments;
    if (!timeout) {
      timeout = setTimeout(() => {
        timeout = null;
        func.apply(context, args);
      }, wait);
    }
  };
}

# 6、项目实际应用

<head>
  <style>
    div {
      height: 150px;
      line-height: 150px;
      text-align: center;
      color: #fff;
      background-color: skyblue;
      font-size: 80px;
    }
    h2 {
      margin: 10px 0;
    }
    p {
      color: #666;
      margin: 20px 0;
    }
    p.title {
      font-size: 17px;
      font-weight: bold;
    }
  </style>
</head>
<body>
  <p class="title">
    说明:鼠标在以下元素不断移动,将会不断执行一个数值累加事件,但中间分别加入了防抖和节流函数。
  </p>
  <h2>防抖</h2>
  <p>在鼠标停止移动后300ms执行一次数值累加事件。</p>
  <div id="content">0</div>
  <h2>节流</h2>
  <p>在鼠标移动过程中,每300ms执行一次数值累加事件。</p>
  <div id="content2">0</div>
  <script>
    // 防抖函数
    function debounce(func, wait) {
      let timeout = null;
      return function () {
        let context = this;
        let args = arguments;
        if (timeout) clearTimeout(timeout);
        timeout = setTimeout(() => {
          func.apply(context, args);
        }, wait);
      };
    }

    // 测试 debounce 防抖函数
    let num = 1;
    let content = document.getElementById("content");
    function count() {
      content.innerHTML = num++;
    }
    content.onmousemove = debounce(count, 300);

    // 节流函数
    function throttle(func, wait) {
      let timeout = null;
      return function () {
        let context = this;
        let args = arguments;
        if (!timeout) {
          timeout = setTimeout(() => {
            timeout = null;
            func.apply(context, args);
          }, wait);
        }
      };
    }

    // 测试 throttle 节流函数
    let num2 = 1;
    let content2 = document.getElementById("content2");
    function count2() {
      content2.innerHTML = num2++;
    }
    content2.onmousemove = throttle(count2, 300);
  </script>
</body>

# 代码效果演示:

image-20220407051123329

上次更新时间: 6/8/2023, 9:23:17 PM

大厂最新技术学习分享群

大厂最新技术学习分享群

微信扫一扫进群,获取资料

X