防抖(Debounce)与节流(Throttle)------作为前端性能优化的技巧之一,能有效解决高频事件引发的性能问题。
核心问题:高频事件的性能瓶颈
当遇到以下场景时:
- 窗口缩放(resize)
- 输入框实时搜索(input)
- 页面滚动(scroll)
- 鼠标移动(mousemove)
这些事件可能每秒触发 几十次甚至上百次。若每次触发都执行复杂操作(如 DOM 操作、网络请求),会导致:
- 页面卡顿甚至崩溃
- 不必要的资源消耗
- 用户体验急剧下降
解决方案对比:防抖 vs 节流
防抖(Debounce) - "等你说完我再响应"
原理 :
事件触发后等待固定时间,若期间无新触发则执行;若期间有新触发,则重置等待时间。
生活比喻 :
电梯关门机制------最后一个人进入后等待几秒,若期间有人进来则重新计时关门。
代码实现:
javascript
function debounce(func, delay) {
let timer;
return function(...args) {
clearTimeout(timer); // 清除上次定时器
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
// 使用示例
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', debounce(fetchResults, 300));
适用场景:
- 搜索框输入(用户停止输入后再请求)
- 窗口 resize 结束后的布局计算
- 表单验证(输入完成再校验)
节流(Throttle) - "按节奏响应"
原理 :
在固定时间间隔内,无论事件触发多少次,只执行一次。
生活比喻 :
地铁进站闸机------每分钟最多通过 30 人,即使有 100 人排队也要按节奏放行。
代码实现:
javascript
function throttle(func, interval) {
let lastTime = 0;
return function(...args) {
const now = Date.now();
if (now - lastTime >= interval) {
func.apply(this, args);
lastTime = now;
}
};
}
// 使用示例
window.addEventListener('scroll', throttle(handleScroll, 200));
适用场景:
- 滚动加载(固定间隔检测位置)
- 鼠标移动跟踪(如拖拽元素)
- 射击游戏中的子弹发射冷却
关键差异对比表
特性 | 防抖(Debounce) | 节流(Throttle) |
---|---|---|
执行时机 | 事件停止后执行 | 固定间隔执行 |
执行次数 | 停止前只执行最后一次 | 间隔内至少执行一次 |
本质区别 | 重置等待时间 | 冷却时间控制 |
适用场景 | 结果导向型(如搜索) | 过程控制型(如动画) |
高级应用技巧
-
组合使用:
javascript// 滚动时每200ms最多执行一次,但停止滚动后额外执行一次 window.addEventListener('scroll', throttle(debounce(finalAction, 200), 200));
-
立即执行版防抖:
javascriptfunction debounceImmediate(func, delay) { let timer; return function(...args) { const shouldCallNow = !timer; clearTimeout(timer); timer = setTimeout(() => { timer = null }, delay); if (shouldCallNow) func.apply(this, args); }; }
-
RAF 节流(适合动画):
javascriptconst rafThrottle = func => { let ticking = false; return (...args) => { if (!ticking) { requestAnimationFrame(() => { func.apply(this, args); ticking = false; }); ticking = true; } }; };
实际工程建议
-
参数调优:
- 搜索防抖:300ms(平衡响应速度与性能)
- 滚动节流:100-200ms(保持流畅度)
- 动画场景:使用
requestAnimationFrame
-
避免过度优化 :
简单事件(如按钮点击)无需使用
-
框架集成 :
Vue/React 中建议封装为自定义 Hook/Directive:
js// Vue指令 Vue.directive('throttle', { inserted(el, binding) { el.addEventListener('click', throttle(binding.value, 1000)); } })
-
调试技巧 :
添加执行计数器验证触发频率:
javascriptconst trackedFn = throttle(() => { console.log(`执行次数:${++count}`); }, 200);
可视化理解
markdown
事件触发: |||||||||||||||||||||||||||||||| (连续触发)
防抖执行点: | (停止后执行)
节流执行点: | | | | | (固定间隔执行)
掌握防抖与节流,标志着开发者从功能实现进阶到性能优化层面。合理运用可使页面性能提升 3-5 倍,特别是在低端移动设备上效果显著。