javascript中什么是防抖和节流_它们如何提升性能【教程】
技术百科
夢幻星辰
发布时间:2026-01-28
浏览: 次 防抖与节流是事件响应策略:防抖只执行最后一次触发(如搜索框停顿后请求),节流则按固定间隔执行(如滚动中每200ms检查位置),二者均用于避免高频无意义调用,而非直接优化CPU或内存性能。
防抖和节流不是“性能优化技巧”,而是「事件响应策略」
它们不直接提升 CPU 或内存性能,而是防止函数被高频、无意义地调用——比如用户狂输 10 个字,input 事件触发 10 次,你却发了 10 次搜索请求;或者拖拽窗口时 resize 每毫秒触发几十次,你却反复重算 DOM 尺寸。真正拖慢页面的,是这些本可跳过的逻辑执行,而非事件本身。
防抖:debounce(fn, delay) —— 只信“最后一击”
每次触发都清掉旧定时器,只在停止触发 delay 毫秒后执行一次。适合“结果比过程重要”的场景:
- 搜索框联想:用户打完 “react” 停顿 300ms 后才查,中间删改都不发请求
- 表单校验(邮箱格式):输入中不提示,光标移出或停顿时再验
- 按钮防重复提交:点击后立刻禁用 + 防抖,避免双击触发两次 API
⚠️ 容易踩的坑:
-
debounce返回的是新函数,不能在addEventListener里每次写debounce(handleInput, 300),否则每次渲染都新建闭包,clearTimeout失效 → 必须提前定义并复用:const debouncedInput = debounce(handleInput, 300) - 没传
this和参数:原始事件回调里的this是 DOM 元素,但防抖函数里会丢失 → 必须用fn.apply(this, arguments)或展开参数 -
delay设太小(如 50ms)≈ 没防抖;设太大(如 800ms)用户会明显感知延迟 → 搜索建议推荐 200–300ms,表单校验可设 400–500ms
节流:throttle(fn, interval) —— 要“节奏感”,不要“全漏掉”
保证

interval 毫秒执行一次,不管触发多密。适合“需要感知过程但不能太密”的交互:
-
scroll监听吸顶或懒加载:滚动中每 200ms 检查一次 scrollTop,既不卡顿也不错过关键位置 - 鼠标拖拽更新坐标:canvas 绘图、自定义 slider,不需要每帧都算,16ms(60fps)或 50ms 更合理
-
mousemove实时预览:避免鼠标划过时疯狂重绘缩略图
⚠️ 容易踩的坑:
- 时间戳版(推荐)首次立即执行,但若需“首次也等间隔”,得用定时器版(带
leading/trailing控制) - 别把
interval设成 0 或负数 —— 会导致无限循环或不执行 - 在 Vue/React 中,别在
render或useEffect里动态生成节流函数,同样会破坏引用稳定性 → 应提至组件外或用useCallback缓存
选错就等于交互逻辑错:防抖 vs 节流,本质是业务语义问题
不是“哪个更快”,而是“你要响应什么”:
- 用户 resize 窗口:用防抖 —— 等他拖完再重排布局,稳
- 用户 scroll 页面想实时显示“已滚动高度百分比”:用节流 —— 防抖会卡住不动,直到他停手,体验断层
- 游戏里按空格射击:用节流(
interval=200ms)限制射速,不是防抖 —— 防抖会让连按变单发,节流才能实现“每 200ms 最多一发”的节奏
真实项目中,lodash 的 _.debounce 和 _.throttle 已处理取消、立即执行、this 绑定等边界,比手写更可靠;但前提是理解它们为何这样设计 —— 否则连配置项都看不懂,比如 leading: true 是啥意思,maxWait 解决什么问题。
# ai
# 的是
# 也不
# 表单
# 首次
# 而非
# 性能优化
# app
# 鼠标
# 拖拽
# input
# 循环
# javascript
# java
# 事件
# this
# 联想
# 闭包
# dom
# canva
# const
# 懒加载
# 邮箱
# 重绘
# react
# vue
# canvas
# 无意义
# 你却
# 防抖
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- 微信短链接怎么还原php_用浏览器开发者工具抓包获
- Go语言中slice追加操作的底层共享机制详解
- 如何使用Golang实现负载均衡_分发请求到多个服
- 如何使用Golang实现RPC序列化与反序列化_G
- 如何使用Golang defer优化性能_减少不必
- Windows服务启动类型恢复方法_错误修改导致的
- Win11怎么设置麦克风权限_允许应用访问Win1
- 如何在 ACF 中正确更新嵌套多层 Group 字
- Win10如何设置双wan路由器 Win10双wa
- Win10怎样清理C盘Steam游戏缓存_Win1
- 如何使用Golang实现云原生应用弹性伸缩_自动应
- Win11怎么查看激活状态_查询Windows 1
- Win11蓝牙开关不见了怎么办_Win11蓝牙驱动
- C#如何在一个XML文件中查找并替换文本内容
- Python实现图数据库操作_Neo4j核心CRU
- Golang如何实现基本的用户注册_Golang用
- Windows10如何更改鼠标灵敏度_Win10鼠
- 如何使用Golang log记录不同级别日志_Go
- Win11怎么关闭系统透明度_Windows11个
- Python文件操作优化_大文件与流处理解析【教程
- Win11怎么压缩文件 Win11自带压缩解压功能
- Mac如何修复应用程序权限问题_Mac磁盘工具修复
- Win11怎么开启专注模式_Windows11时钟
- Drupal 中 HTML 链接被双重转义导致渲染
- Win11如何隐藏桌面图标 Win11一键隐藏/显
- Win11怎么关闭贴靠布局_Win11禁用窗口最大
- c++怎么用jemalloc c++替换默认内存分
- Win10如何优化内存使用_Win10内存优化技巧
- 如何使用Golang template生成文本模板
- Win11怎么查看wifi信号强度_检测Windo
- c++ std::atomic如何保证原子性 c+
- Win11怎么设置默认浏览器Chrome_Wind
- Win11怎样安装剪映专业版_Win11安装剪映教
- Python异步编程高级项目教程_asyncio协
- C++中的std::shared_from_thi
- c++怎么设置线程优先级与cpu亲和性_c++ 多
- Win10怎么卸载剪映_Win10彻底卸载剪映方法
- 如何在JavaScript中动态拼接PHP的bas
- 如何快速验证Golang安装是否成功_运行go v
- Avalonia如何实现跨窗口通信 Avaloni
- c# 如何深拷贝和浅拷贝
- Linux如何申请SSL免费证书_Linux下Ce
- 如何优化Golang Web性能_Golang H
- 短链接怎么自定义还原php_修改解码规则适配需求【
- Win10系统更新错误0x80240034怎么办
- Win11怎么更改文件夹图标_自定义Win11文件
- c++ std::future和std::prom
- c++怎么调用nana库开发GUI_c++ 现代风
- Windows的便笺功能如何使用?(桌面备忘技巧)
- 如何用正则与预处理高效拦截带干扰符的恶意域名

QQ客服