当前位置: 首页 > article >正文

防抖与节流:优化高频事件的两种利器

一、引言

在现代前端开发中,用户交互的实时性和流畅性至关重要。然而,某些高频事件(如输入框输入、窗口缩放、滚动等)可能会频繁触发回调函数,导致性能问题。例如,以下代码中的输入框会在每次输入时触发 oninput 事件:

<div>
    请输入你想搜索的内容: <input type="text" name="search" id="search">
</div>
<script>
    let input = document.querySelector('#search');
    input.oninput = function () {
        console.log("===> input回调事件触发了" + this.value);
    }
</script>

用户每输入一个字符,控制台会输出日志,这可能会导致页面卡顿或请求过多。正确的方式应该是用户输入完成后,才触发一次即可。为了解决这类问题,我们可以使用 防抖(Debounce) 和 节流(Throttle) 技术来优化高频事件的触发频率。


二、基本概念
1. 防抖(Debounce)
  • 定义与核心思想
    防抖的核心思想是:在事件被触发后,等待一段时间(如 500ms),如果在这段时间内没有再次触发事件,则执行回调函数。如果在这段时间内事件再次被触发,则重新计时。

  • 类比解释
    想象电梯关门的场景:当有人进入电梯时,电梯门不会立即关闭,而是等待一段时间(如 5 秒)。如果在这段时间内又有人进入,电梯会重新等待 5 秒,直到没有人进入后才关门。

  • 适用场景

    • 搜索框输入建议(等待用户停止输入后再请求)
    • 窗口缩放事件(等待用户停止调整窗口大小后再重新布局)
2. 节流(Throttle)
  • 定义与核心思想
    节流的核心思想是:在事件被触发后,固定一段时间(如 1000ms)内只执行一次回调函数。无论事件触发多少次,回调函数都会按照固定的时间间隔执行。

  • 类比解释
    想象游戏中的技能冷却时间(CD):释放技能后,必须等待一段时间才能再次释放,无论玩家按了多少次技能键。

  • 适用场景

    • 滚动加载更多内容(每隔一段时间检查滚动位置)
    • 鼠标移动事件(每隔一段时间更新鼠标位置)

三、Lodash 库的实现

Lodash 是一个流行的 JavaScript 工具库,提供了现成的防抖和节流函数,使用起来非常方便。

1. _.debounce() 方法
  • 功能:创建一个防抖函数,延迟执行回调。
  • 参数
    • func:需要防抖的回调函数。
    • wait:等待时间(单位:毫秒)。
    • options:可选配置(如 leading 和 trailing)。
  • 示例
input.oninput = _.debounce(function() {
    console.log("防抖后的输入值:" + this.value);
}, 500);
2. _.throttle() 方法
  • 功能:创建一个节流函数,固定时间间隔执行回调。
  • 参数
    • func:需要节流的回调函数。
    • wait:时间间隔(单位:毫秒)。
    • options:可选配置(如 leading 和 trailing)。
  • 示例
window.onscroll = _.throttle(function() {
    console.log("滚动事件触发,当前位置:" + window.scrollY);
}, 1000);

四、对比与选择
1. 防抖 vs 节流的差异
  • 执行时机

    • 防抖:在事件停止触发后执行。
    • 节流:在固定时间间隔内执行。
  • 适用场景

    • 防抖:适合处理最终状态(如输入框的最终值)。
    • 节流:适合处理过程状态(如滚动事件)。
2. 如何选择
  • 如果需要响应最终结果,选择防抖。
  • 如果需要均匀分布事件触发,选择节流。
3. 性能影响
  • 防抖和节流都能有效减少回调函数的执行次数,从而提升性能。
  • 防抖更适合减少不必要的计算或请求,节流更适合平滑高频事件的触发。

五、结合示例代码的实战
1. 原始代码的问题

以下代码中,输入框的 oninput 事件和按钮的 onclick 事件会频繁触发,可能导致性能问题:

  • 输入框每次输入都会触发回调,控制台输出大量日志(使用防抖解决)。
let input = document.querySelector('#search');
input.oninput = function () {
    console.log("===> input回调事件触发了" + this.value);
}
  • 按钮每次点击都会触发回调,计数器快速增加(使用节流解决)。
let btn = document.querySelector('#btn');
let span = document.querySelector('span');
let count = 0;
btn.onclick = function () {
    count++;
    span.innerHTML = count;
}
2. 防抖改造示例

使用 Lodash 的 _.debounce() 方法优化输入框事件:

  • 延迟 500ms 后执行回调。
  • 如果用户在 500ms 内继续输入,则重新计时。
input.oninput = _.debounce(function () {
    console.log("防抖后的输入值:" + this.value);
}, 500);

最终效果:快速输入时,控制台只会在用户停止输入 500ms 后输出最终的输入值。

3. 节流改造示例

使用 Lodash 的 _.throttle() 方法优化按钮点击事件:

  • 每隔 1000ms 最多执行一次回调。
  • 无论用户点击多少次,计数器每秒最多增加一次。
btn.onclick = _.throttle(function () {
    count++;
    span.innerHTML = count;
}, 1000);

最终效果:快速点击按钮时,计数器每秒最多增加一次。

4. 完整代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>防抖与节流示例</title>
    <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
</head>
<body>
    <div>
        <h1>防抖</h1>
        请输入你想搜索的内容: <input type="text" name="search" id="search">
    </div>
    <div>
        <h1>节流</h1>
        <p>我是计数器 <span>0</span></p>
        <button id="btn">点我 +1 </button>
    </div>
    <script>
        // 防抖部分
        let input = document.querySelector('#search');
        input.oninput = _.debounce(function () {
            console.log("防抖后的输入值:" + this.value);
        }, 500);

        // 节流部分
        let btn = document.querySelector('#btn');
        let span = document.querySelector('span');
        let count = 0;
        btn.onclick = _.throttle(function () {
            count++;
            span.innerHTML = count;
        }, 1000);
    </script>
</body>
</html>

通过本示例,我们可以看到:

  • 防抖 适用于需要等待用户操作结束后再执行的场景(如输入框搜索)。
  • 节流 适用于需要限制操作频率的场景(如按钮点击、滚动事件)。

这两种技术都能有效优化高频事件的性能问题,提升用户体验。


http://www.kler.cn/a/518607.html

相关文章:

  • 工业数据分析:解锁工厂数字化的潜力
  • 基于回归分析法的光伏发电系统最大功率计算simulink建模与仿真
  • 乒乓球日常烧拍日记之四海绵支撑
  • Django 日志配置实战指南
  • React第二十五章(受控组件/非受控组件)
  • C#,入门教程(07)——软件项目的源文件与目录结构
  • 「pandas」python pandas 初步、数据结构Series、DataFrame、MultiIndex
  • 【最小堆】【动态规划】力扣264. 丑数 II
  • 【Elasticsearch】eland是啥?
  • F#语言的图形用户界面
  • MarsCode青训营打卡Day11(2025年1月24日)|稀土掘金-373.字母出现次数的统计
  • 【OpenGL】OpenGL游戏案例(一)
  • Leetcode-两数之和
  • 【第六天】零基础入门刷题Python-算法篇-数据结构与算法的介绍-一种常见的贪心算法(持续更新)
  • flutter跨端UI框架简介
  • 简识JVM中的STW
  • 【二叉树】4. 判断一颗二叉树是否是平衡二叉树。5. 对称二叉树。6. 二叉树的构建及遍历 7. 二叉树的分层遍历 。
  • 使用 .NET Core 6.0 Web API 上传单个和多个文件
  • 12、MySQL锁相关知识
  • 分布式系统架构怎么搭建?
  • Flutter_学习记录_导航和其他
  • 小程序电商运营内容真实性增强策略及开源链动2+1模式AI智能名片S2B2C商城系统源码的应用探索
  • Linux之NetLink学习笔记
  • docker Ubuntu实战
  • 计算机图形学:实验四 带纹理的OBJ文件读取和显示
  • vue3自定义表格生成动态列