前端函数防抖(Debounce)完整讲解 - 从原理、应用到完整实现

在这里插入图片描述

🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志
🎐 个人CSND主页——Micro麦可乐的博客
🐥《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战
🌺《RabbitMQ》专栏19年编写主要介绍使用JAVA开发RabbitMQ的系列教程,从基础知识到项目实战
🌸《设计模式》专栏以实际的生活场景为案例进行讲解,让大家对设计模式有一个更清晰的理解
🌛《开源项目》本专栏主要介绍目前热门的开源项目,带大家快速了解并轻松上手使用
✨《开发技巧》本专栏包含了各种系统的设计原理以及注意事项,并分享一些日常开发的功能小技巧
💕《Jenkins实战》专栏主要介绍Jenkins+Docker的实战教程,让你快速掌握项目CI/CD,是2024年最新的实战教程
🌞《Spring Boot》专栏主要介绍我们日常工作项目中经常应用到的功能以及技巧,代码样例完整
🌞《Spring Security》专栏中我们将逐步深入Spring Security的各个技术细节,带你从入门到精通,全面掌握这一安全技术
如果文章能够给大家带来一定的帮助!欢迎关注、评论互动~

前端函数防抖(Debounce)完整讲解 - 从原理、应用到完整实现

  • 1. 前言
  • 2. 为什么使用防抖?
  • 3. 函数防抖的应用场景
  • 4. 完整代码实现
    • ❶ 基础防抖函数
    • ❷ 使用示例(输入框搜索)
    • ❸ React Hooks 防抖实现
    • ❹ 使用 Lodash 的 _.debounce
  • 5. 高阶技巧与注意事项
  • 6. 结语

1. 前言

在我们日常前端开发中,高频触发的事件(如输入框输入、窗口缩放、滚动事件)可能导致性能问题甚至引发BUG。函数防抖(debounce)是一种常见且高效的性能优化手段,用于限制高频事件触发下的函数调用次数,从而减少不必要的计算、网络请求或 DOM 操作。

本文博主将带着小伙伴一起深入解析防抖机制的原理、六大应用场景,并提供可直接复用的代码示例。


2. 为什么使用防抖?

在这里插入图片描述
我们来看看你是否也遇到这样的问题:

当用户快速连续触发事件时,例如:

  • 搜索框每输入一个字符立即请求接口
  • 窗口缩放时频繁更新布局
  • 疯狂点击提交按钮

会导致:

  • 性能浪费:不必要的计算/请求
  • 数据错乱:异步请求响应顺序不可控
  • 用户体验差:界面卡顿或闪烁

函数防抖的核心思想是在连续触发的事件停止后,仅执行最后一次调用,以避免频繁触发带来的性能问题。
延迟执行 + 重置计时器:在事件被触发后等待指定时间(如300ms),若期间没有再次触发,则执行函数;若期间重复触发,则重新开始计时


3. 函数防抖的应用场景

场景示例解决方案
搜索建议输入框联想词查询停止输入300ms后发起请求
按钮提交防止重复提交订单点击后禁用按钮直至操作完成
窗口调整响应式布局计算窗口停止调整后执行计算
滚动加载无限滚动加载更多停止滚动后触发检测
画布绘制实时预览图形渲染停止拖拽后更新渲染
表单验证密码强度实时检测输入结束再进行复杂校验

为了让大家更清晰了解其应用场景,我们例举几个说明:

1、输入框实时搜索
在用户输入关键词时触发搜索接口,若不加限制,每次 keyup 都会发起请求,极易导致接口压力过大。使用防抖后,只在用户停止输入(如 300ms)后才发送请求,有效降低调用次数

2、按钮防连点
对于提交表单或支付按钮,连续点击可能导致多次提交。给点击事件绑定防抖函数,可在用户短时间内多次点击时只执行一次提交操作

3、窗口大小调整(resize)
当页面布局需根据窗口大小实时计算或重绘时,resize 事件会频繁触发,添加防抖能减少重绘次数,提升性能

4、滚动监听
结合无限滚动或懒加载,当用户滚动页面时应控制数据加载频率,避免重复请求或过度渲染


4. 完整代码实现

防抖函数通过内部维护一个定时器 ID,每次调用时先清除之前的定时器,再启动一个新的延迟执行定时器;只有在最后一次调用后的延迟时间到达后,才真正执行目标函数

❶ 基础防抖函数

先看一个简单实现:

/*** 防抖函数* @param {Function} fn  需要防抖的函数* @param {number} delay 延迟时间(毫秒)* @returns {Function}    包装后的防抖函数*/
function debounce(fn, delay = 300) {let timer = nullreturn function(...args) {// 每次触发时清除之前的计时器if (timer) clearTimeout(timer)// 设置新的计时器timer = setTimeout(() => {fn.apply(this, args)  // 确保正确的this上下文timer = null}, delay)}
}

上述代码利用 JavaScript 闭包,让每个防抖函数维护独立的 timeoutId,在多次调用时只有最后一次延迟结束后触发

❷ 使用示例(输入框搜索)

<input type="text" id="searchInput"><script>
const searchInput = document.getElementById('searchInput')// 原始请求函数
function fetchSearchResult(keyword) {console.log(`搜索关键词: ${keyword}`)// 实际调用API接口...
}// 包装为防抖版本(500ms延迟)
const debouncedFetch = debounce(fetchSearchResult, 500)// 绑定输入事件
searchInput.addEventListener('input', (e) => {debouncedFetch(e.target.value.trim())
})
</script>

❸ React Hooks 防抖实现

import { useCallback, useEffect, useRef } from 'react'// 自定义防抖Hook
function useDebounce(fn, delay) {const timerRef = useRef(null)const debouncedFn = useCallback((...args) => {if (timerRef.current) clearTimeout(timerRef.current)timerRef.current = setTimeout(() => {fn(...args)timerRef.current = null}, delay)}, [fn, delay])// 组件卸载时清除计时器useEffect(() => {return () => {if (timerRef.current) clearTimeout(timerRef.current)}}, [])return debouncedFn
}// 在组件中使用
function SearchBox() {const [keyword, setKeyword] = useState('')// 防抖请求函数const debouncedSearch = useDebounce((value) => {console.log('实际搜索:', value)}, 500)const handleChange = (e) => {setKeyword(e.target.value)debouncedSearch(e.target.value)}return <input value={keyword} onChange={handleChange} />
}

❹ 使用 Lodash 的 _.debounce

在实际项目中,为了减少手写错误并获得更丰富的功能(如 leading、trailing、cancel、flush 等选项),推荐使用成熟的工具库 Lodash_.debounce 方法

# 安装 lodash.debounce 子模块
npm install lodash.debounce

快速使用:

import debounce from 'lodash.debounce';/** * 在搜索框中使用防抖 * 当用户停止输入 300ms 后才触发搜索 */
const searchInput = document.getElementById('search');
function onSearch(query) {// 发送搜索请求console.log('搜索关键词:', query);
}
const debouncedSearch = debounce(onSearch, 300, { leading: false, trailing: true });searchInput.addEventListener('input', (e) => {debouncedSearch(e.target.value);
});

参数说明

  • leading: 是否在延迟开始前调用一次,默认 false。
  • trailing: 是否在延迟结束后调用一次,默认 true。
  • 返回的函数还拥有 cancel() 和 flush() 方法,可在需要时取消或立即执行待定调用

5. 高阶技巧与注意事项

  1. 立即执行模式
    在不使用Lodash库时,我们也可以添加立即执行选项,首次触发立即执行,后续触发进入防抖

    function debounce(fn, delay, immediate = false) {let timerreturn function(...args) {if (immediate && !timer) fn.apply(this, args)if (timer) clearTimeout(timer)timer = setTimeout(() => {if (!immediate) fn.apply(this, args)timer = null}, delay)}
    }
    
  2. 防抖与节流区别

    • 防抖(Debounce):等电梯(最后一个人进来后等10秒关门)
    • 节流(Throttle):发短信(每60秒只能发一次)
  3. 性能优化

    • 高频事件(如mousemove)建议结合requestAnimationFrame
    • 避免在防抖函数中处理大型对象

6. 结语

函数防抖是前端性能优化中的一项基础技术,适用于各种需要限制高频事件调用的场景,通过本文介绍的 定时器逻辑 或成熟的 Lodash 工具库,就能快速落地。通过本文的代码示例,小伙伴们可以快速将其应用到实际项目中。当遇到高频触发事件时,不妨先思考:这个场景是否需要防抖?

如果你在实践过程中有任何疑问或更好的扩展思路,欢迎在评论区留言,最后希望大家 一键三连 给博主一点点鼓励!


前端技术专栏回顾:

01【前端技术】 ES6 介绍及常用语法说明
02【前端技术】标签页通讯localStorage、BroadcastChannel、SharedWorker的技术详解
03 前端请求乱序问题分析与AbortController、async/await、Promise.all等解决方案
04 前端开发中深拷贝的循环引用问题:从问题复现到完美解决
05 前端AJAX请求上传下载进度监控指南详解与完整代码示例
06 TypeScript 进阶指南 - 使用泛型与keyof约束参数
07 前端实现视频文件动画帧图片提取全攻略 - 附完整代码样例
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/news/906642.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

服务接口鉴权与内部认证:自定义注解与AOP实现的企业级实践

本文深入解析企业级系统中接口安全管控的核心需求&#xff0c;提出基于Spring AOP与自定义注解的轻量级鉴权方案。通过解构注解元数据定义、切面拦截逻辑、上下文传递机制等关键技术环节&#xff0c;系统阐述零侵入式鉴权体系的构建路径。结合金融支付网关、多租户SaaS平台、物…

26考研|高等代数:线性变换

前言 线性变换这一章节是考频较高的一部分&#xff0c;此部分涉及考点较多&#xff0c;涉及的考题也较多&#xff0c;学习线性变换时&#xff0c;应该注意搭建线性变换与矩阵之间的联系&#xff0c;掌握如何利用矩阵表示一个线性变换结构&#xff0c;同时介绍了最简单的线性变…

电磁兼容(EMC)仿真(精编版)

写在前面 本系列文章主要讲解电磁兼容(EMC)仿真的相关知识,希望能帮助更多的同学认识和了解电磁兼容(EMC)仿真。 若有相关问题,欢迎评论沟通,共同进步。(*^▽^*) 随着产品复杂性和密集度的提高以及设计周期的不断缩短,在设计周期的后期解决电磁兼容性(EMC)问题变得…

解决:dpkg: error: dpkg frontend lock is locked by another process

1、等待其他进程完成 如果后台有其他包管理操作&#xff08;如自动更新、软件安装等&#xff09;&#xff0c;等待几分钟再重试。 可以通过以下命令查看是否有相关进程&#xff1a; ps aux | grep -E apt|apt-get|dpkg 2、强制终止占用锁的进程 如果确认没有其他包管理操作&…

LVGL(lv_textarea文本框控件)

文章目录 一、lv_textarea 是什么&#xff1f;二、基本用法1. 创建 lv_textarea 对象2. 设置提示文字&#xff08;占位符&#xff09;3. 设置最大长度4. 设置密码模式&#xff08;显示为\*号&#xff09;5. 获取和设置内容6. 配合虚拟键盘使用&#xff08;常用于触摸屏&#xf…

【Java高阶面经:数据库篇】18、分布式事务:如何在分库分表中实现高性能与一致性?

一、分布式事务核心挑战:分库分表下的一致性困境 在分布式系统架构中,分库分表通过将数据分散存储提升了扩展性和性能,但却打破了传统单库事务的边界,使得分布式事务成为保障数据一致性的核心难题。其挑战主要体现在以下三方面: 1.1 ACID特性的分布式撕裂 原子性(Atomi…

【云呐】房地产企业固定资产如何管理

房产类固定资产如办公楼、门面房、宿舍楼、库房等&#xff0c;价值高、使用年限长、权属复杂、变更流程多&#xff0c;是企业最为关键的资产类型之一。管理房产类资产不仅要“看得到”&#xff0c;更要“管得住”。 房产资产管理应从权属明确开始。固定资产管理系统支持房产资产…

oracle数据库生成awr报告,排查数据库服务器CPU100%,系统卡顿,慢sql,根据sqlid查询关键信息,如会话SID,客户端机器名

AWR报告简介 AWR是Oracle 10g版本推出的特性,全称叫做 Automatic Workload Repository 全自动负载信息库 。Oracle启动后,会有后台进程定时采集并保存系统快照信息,也可以手工创建快照。AWR通过对比两个时间点的快照信息,生成该时间段的AWR报告,帮助DBA或开发人员了解 Ora…

kafka吞吐量提升总结

前言 原本自以为阅读了很久kafka的源码&#xff0c;对于kafka的了解已经深入到一定程度了&#xff0c;后面在某大厂的面试中&#xff0c;面试官询问我&#xff0c;如果需要提升kafka的性能&#xff0c;应该怎么做&#xff0c;我发现我能答上来的点非常的少&#xff0c;也暴露了…

鸿蒙 HarmonyOS NEXT 系统 Preference 首选项使用全解析

鸿蒙HarmonyOS系统Preference首选项使用全解析 大家好&#xff0c;我是威哥。在鸿蒙应用开发里&#xff0c;用户偏好设置的管理是极为重要的一环。HarmonyOS为我们提供了Preference组件&#xff0c;它能让我们轻松实现应用设置界面&#xff0c;对用户首选项进行高效管理。接下…

xdc约束学习

对clk的约束 //约束clk为 125M Hz create_clock -period 8.000 -name gt_refclk1_p -waveform {0.000 4.000} [get_ports gt_refclk1_p] 伪时钟路径&#xff0c;用于两个时钟域之间数据的交互 单边性&#xff08;unateness&#xff09;对于时序很重要&#xff0c;因为它指定的…

在 Ubuntu 虚拟机中实现 HTML 表单与 C 语言 HTTP 服务器交互

一、环境说明 系统&#xff1a;Ubuntu 虚拟机&#xff08;已安装基本开发工具&#xff0c;如 GCC&#xff09;目标&#xff1a;通过 C 语言服务器托管 HTML 表单页面&#xff0c;并实现数据提交交互 二、核心文件准备 1. 创建 HTML 表单页面&#xff08;xunfei.html&#xf…

LVS 负载均衡集群应用实战

前提:三台虚拟机,有nginx,要做负载 1. LVS-server 安装lvs管理软件 [root@lvs-server ~]# yum -y install ipvsadm 程序包:ipvsadm(LVS管理工具) 主程序:/usr/sbin/ipvsadm 规则保存工具:/usr/sbin/ipvsadm-save > /path/to/file 配置文件:/etc/sysconfig/ipvsad…

鸿蒙进阶——Framework之Want 隐式匹配机制概述

文章大纲 引言一、Want概述二、Want的类型1、显式Want2、隐式Want3、隐式Want的匹配 三、隐式启动Want 源码概述1、有且仅有一个Ability匹配2、有多个Ability 匹配需要弹出选择对话框3、ImplicitStartProcessor::ImplicitStartAbility3.1、GenerateAbilityRequestByAction3.1.1…

Rules and Monetization

The system creates rules that allow them to monetize. The system doesn’t just enforce rules — it creates them strategically to monetize control. &#x1f527; How It Works: Invent a rule (e.g., “You need a permit to sell food.”)Claim it’s for safety …

java中string类型的list集合放到redis的5种数据类型的那种比较合适呢,可以用StringRedisTemplate实现

在Java中&#xff0c;如何将一个String类型的List集合存储到Redis中&#xff0c;并且应该选择Redis的哪种数据类型。同时&#xff0c;用户还问到是否可以使用StringRedisTemplate来实现。 首先&#xff0c;我需要回忆一下Redis的5种主要数据类型&#xff1a;字符串&#xff08;…

基于DQN的学习资源难度匹配智能体

基于DQN的学习资源难度匹配智能体 下面我将实现一个基于DQN(深度Q网络)的智能体,用于根据用户的学习表现动态匹配适合难度的学习资源。这个系统可以应用于在线教育平台,根据用户的历史表现自动调整推荐资源的难度级别。 1. 环境设置 首先我们需要定义学习环境,这里我创建…

OrangePi Zero2开发指南:从SDK获取到交叉编译全流程详解

一、OrangePi Zero2 SDK说明 SDK 全称 Software Development Kit&#xff0c;即软件开发工具包。一般包括了一些工具&#xff08;如交叉编译工具链&#xff09;、库、文档和示例代码。香橙派的Linux SDK其实指的就是 orangepi-build 这套代码集&#xff0c;orangepibuild 在脚…

MATLAB NLP 工具箱 文本预处理教程

文章目录 前言一、文本预处理核心步骤二、MATLAB 实现示例三、高级预处理技术四、预处理流程整合五、性能优化与注意事项六、实战案例&#xff1a;IMDB 影评预处理 前言 以下是 MATLAB 自然语言处理 (NLP) 工具箱的文本预处理教程&#xff0c;涵盖核心步骤、代码实现及最佳实践…

大模型的量化与双重量化(1)

文章目录 大模型量化的含义和作用什么是量化量化的作用具体示例 双重量化的含义和作用什么是双重量化双重量化的具体实现双重量化的作用具体示例对比实际应用场景 大模型量化的含义和作用 什么是量化 量化是指将神经网络中的参数&#xff08;权重和激活值&#xff09;从高精度…