掌握了回城和金身的我已经领悟了防抖和节流

355 阅读5分钟

文章正文:


掌握性能优化艺术:深入理解防抖与节流技术

大家好,我是爱分享的小江哥,遥想当年那也是在祖安抖三抖的著名黄金AD选手,那一夜在祖安酣畅淋漓的战斗中我突然悟了,什么是防抖和节流,这TM就是防抖和节流。

在在经典的面试题中,网页性能优化是提升用户体验(==面试官最爱问的==)的关键一环。随着用户对即时反馈和流畅交互的期望日益增长,前端开发者必须采取有效措施减少页面加载时间、提高响应速度。在这场追求极致性能的战役中,出现了两个神器成为所有召唤师必备的基础连招

  • 防抖(Debouncing)
  • 节流(Throttling)

专门为优化频繁触发的事件处理提供了行之有效的解决方案。

第一章:认识事件处理与性能挑战

作为传统AD的爱好者,小江哥深知每一个人都有平凡走A操作的基因,即使是在普通的页面上也能诱发。 当一个用户像UZI一样在你的前端页面疯狂走A的时候(快速点击按钮、连续滚动或调整窗口大小),浏览器会不断接收并处理这些操作(事件)。 但是,频繁的操作会导致不必要的计算负担(无效操作),影响性能从而影响整体体验。

第二章:防抖技术 Debouncing(回城技术)详解

2.1 定义与原理

防抖技术的核心在于合并连续的事件触发,仅在最后一次触发后的一段时间内执行回调函数。这种机制通过引入延迟执行,有效避免了短时间内多次执行同一操作造成的性能损耗。

==简单来说就像回城一样,再次重复的操作会影响整个回城的读条(重新计时)。只会在最后一次按下B键并且读条8秒之后才会执行回城==

function debounce(func, wait) {
    let timeout;
    return function() {
        clearTimeout(timeout);
        timeout = setTimeout(() => func.apply(this, arguments), wait);
    };
}

2.2 实现方法

上述代码展示了防抖的基本实现。当事件被触发时,setTimeout会被不断重置,直到最后一次触发后的wait毫秒,func才会被执行。

2.3 应用场景

  • 搜索框输入建议:用户连续输入时,仅在输入停止后请求搜索建议,减少无谓的API调用。
  • 按钮防重复提交:确保表单提交等关键操作不会因用户快速点击而被多次执行。

2.4 进阶技巧

领先延迟防抖允许首次触发立即执行函数,之后的触发则遵循防抖规则。这在需要即时反馈的场景下尤为适用。

第三章:节流技术(Throttling)全面解析

3.1 定义与原理

与防抖不同,节流保证在固定时间间隔内只执行一次函数,无论期间事件触发多少次。这种方法适用于需要限制函数执行频率的场景。

==简单来说就像金身一样,在金身期间无论怎么按金身都只触发一次。==

3.2 实现方法

function throttle(func, limit) {
    let inThrottle;
    return function() {
        const args = arguments;
        const context = this;
        if (!inThrottle) {
            func.apply(context, args);
            inThrottle = true;
            setTimeout(() => (inThrottle = false), limit);
        }
    };
}

3.3 应用场景

  • 滚动事件处理:保持滚动顺畅,同时限制处理函数的执行频率。
  • 动画控制:确保动画帧率稳定,防止过度渲染。

3.4 高级应用

时间戳法与定时器法是实现节流的两种方式。前者通过记录上次执行时间来判断是否达到执行间隔,后者则依赖setTimeout来控制执行频率,两者各有优劣,根据具体需求选择。

第四章:防抖与节流的抉择

防抖适合于减少不必要的计算,尤其是那些不紧急但计算成本高的操作;而节流则更适用于需要维持一定频率执行,但又不能过于频繁的场景。选择时需考虑事件触发的特性和性能需求。

实战案例分析

假设有一个实时搜索功能,使用防抖可以有效减少不必要的API请求,而在处理滚动事件加载更多内容时,节流能确保平滑滚动体验同时控制数据加载频率。

结语

防抖与节流作为前端性能优化的重要手段,它们在处理高频事件时展现出了强大的效能。掌握这两种技术,不仅能够提升网页性能,还能在用户体验与系统资源之间找到完美的平衡点。鼓励开发者持续学习与实践,探索更多性能优化策略,不断推进前端技术的边界。

附录:相关资源链接

完整测试代码:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Debounce and Throttle Demo</title>
    <style>
      button {
        margin: 10px;
      }
    </style>
  </head>
  <body>
    <h2>防抖(Debounce)示例</h2>
    <input
      type="text"
      id="debounceInput"
      placeholder="在此输入进行防抖测试..."
    />
    <button onclick="handleDebounceClick()">点击防抖</button>
    <h2>节流(Throttle)示例</h2>
    <button id="throttleButton" onclick="handleThrottleClick()">
      点击节流
    </button>

    <script>
      // 防抖函数
      function debounce(func, delay) {
        let timeoutId;
        return function (...args) {
          if (timeoutId) clearTimeout(timeoutId);
          timeoutId = setTimeout(() => {
            func.apply(this, args);
          }, delay);
        };
      }

      // 节流函数
      function throttle(func, limit) {
        let inThrottle;
        return function () {
          const args = arguments;
          const context = this;
          if (!inThrottle) {
            func.apply(context, args);
            inThrottle = true;
            setTimeout(() => (inThrottle = false), limit);
          }
        };
      }

      // 防抖处理函数
      function logDebounce() {
        console.log("防抖触发: ", new Date().getTime());
      }
      const debouncedLog = debounce(logDebounce, 1000);

      // 节流处理函数
      function logThrottle() {
        console.log("节流触发: ", new Date().getTime());
      }
      const throttledLog = throttle(logThrottle, 2000);

      // 为输入框的输入事件添加防抖处理
      document
        .getElementById("debounceInput")
        .addEventListener("input", debouncedLog);

      // 点击按钮触发防抖
      function handleDebounceClick() {
        debouncedLog();
      }

      // 点击按钮触发节流
      function handleThrottleClick() {
        throttledLog();
      }
    </script>
  </body>
</html>