在前端开发中,经常会遇到高频触发的事件,搜索框输入、页面滚动、按钮点击等,如果不对这些事件进行处理,频繁执行回调函数,可能会导致页面卡顿、请求次数过多,影响用户体验和系统性能。
防抖(Debounce)和节流(Throttle) 就是解决高频事件的秘密武器。它们的实现原理是闭包,用法相似,使用场景不同。应该根据实际场景,选择合适的方法进行处理。
为什么需要防抖节流
先从一个实际的例子入手,百度搜索,当你在搜索框输入关键字时,每次输入,都会触发键盘事件,若直接绑定网络请求,就会出现高频请求的问题。
如果不做任何处理,就会出现两个核心问题:
- 执行次数过多:如果用户输入速度快,会在短时间内多次触发网络请求,网络次数过多,不仅服务器压力大,也会浪费前端性能。
- 用户体验失衡:请求过快,频繁发送请求可能会导致响应混乱、页面卡顿;请求过慢,会导致联想建议延迟,影响使用体验
类似的场景还有很多,页面滚动加载、按钮重复提交,这些高频触发事件,都要通过防抖或节流来优化,避免"性能浪费"
这一切的实现,都离不开闭包的支持,利用闭包保留定时器ID,上一次执行时间等状态,让函数能够记住之前的执行状态,从而实现精准的触发控制,这就是防抖节流的核心底层逻辑。
防抖(Debounce): 多次触发,只执行最后一次
什么是防抖
防抖的核心逻辑:**在规定时间内,无论事件触发多少次,都只执行最后一次回调。**触发高频事件之后,函数不会立即执行,而是等待一段时间(延迟时间)后再执行;若在这段时间内事件再次被触发,则重新计时,只有当事件停止触发并且超过要延迟时间,函数才会执行一次。
防抖实现关键
javascript
/**
* 防抖函数
* @param {Function} fn 函数
* @param {Number} delay 间隔
*/
function debounce(fn, delay) {
var timer = null; // 变量(闭包核心):保存定时器ID
return function(args) {
if(timer) clearTimeout(timer); // 每次触发事件,先清除之前的定时器,重置倒计时
var that = this; // 保存当前this指向,避免定时器内this丢失
timer = setTimeout(function(){
fn.call(that, args); // 推迟执行:延迟delay毫秒后,执行目标函数(最后一次触发的回调)
}, delay);
}
}
防抖应用场景
- 搜索框输入联想:用户不断输入,等待用户停止输入后才触发联想请求;
- 输入框实时校验:手机号、邮箱格式等,等待用户输入完成之后再校验,避免输入过程中频繁提示;
- 按钮防止重复提交:例如表单提交按钮,避免用户连续点击发送多次请求;
- 滚动条滚动检测:无需滚动过程中频繁检测,等待滚动停止后,判断滚动条位置。
节流(Throttle):每隔一段时间,只执行一次
什么是节流
节流的核心逻辑:**在规定时间内,无论事件触发多少次,都只执行一次回调。**触发高频事件,限制函数在指定时间间隔内只执行一次,无论事件触发多少次,都会按照固定的频率执行函数。
节流实现关键
javascript
/**
* 节流函数
* @param {Function} fn 函数
* @param {Number} interval 间隔
*/
function throttle(fn, interval) {
var enterTime = Date.now(); //触发时间
return function() {
var that = this, currentTime = Date.now(); // 当前时间
if (currentTime - enterTime >= interval) { //判断是否到了指定间隔
fn.apply(that, args);
enterTime = Date.now(); //更新触发时间
}
}
}
节流应用场景
- 按钮点击:点赞、刷新按钮,限制用户操作频率,防止恶意刷赞;
- 滚动加载更多:用户滚动要页面,设置间隔,检测滚动位置,判断是否需要加载更多数据;
- 鼠标移动:拖拽元素,固定频率更新元素位置,避免更新过于频繁,造成页面卡顿。
防抖和节流的区别
| 特性 | 防抖(Debounce) | 节流(Throttle) |
|---|---|---|
| 核心逻辑 | 等待最后一次触发后,延迟执行一次 | 固定时间间隔内,只执行一次 |
| 执行时机 | 事件停止触发后(延迟结束) | 事件触发过程中(按固定频率) |
| 触发频率 | 取决于事件停止触发的时间,可能很久执行一次 | 固定频率执行,不受事件触发频率影响 |
| 核心目的 | 过滤无效触发,保留最后一次结果 | 控制执行频率,避免过度执行 |
| 通俗比喻 | 电梯关门(有人进就重新计时) | 水龙头滴水(固定时间滴一滴) |
总结
防抖和节流解决问题的核心目的是一致:优化高频事件的性能,避免复杂任务频繁执行,两者的核心区别在于防抖只执行最后一次,节流是固定时间间隔内只执行一次。在实际运用过程中,需要根据不同场景合理选择使用防抖或节流,提升页面性能,优化用户体验。