防抖和节流:解决高频事件性能

0 阅读5分钟

在前端开发中,经常会遇到高频触发的事件,搜索框输入、页面滚动、按钮点击等,如果不对这些事件进行处理,频繁执行回调函数,可能会导致页面卡顿、请求次数过多,影响用户体验和系统性能。

防抖(Debounce)和节流(Throttle) 就是解决高频事件的秘密武器。它们的实现原理是闭包,用法相似,使用场景不同。应该根据实际场景,选择合适的方法进行处理。

为什么需要防抖节流

先从一个实际的例子入手,百度搜索,当你在搜索框输入关键字时,每次输入,都会触发键盘事件,若直接绑定网络请求,就会出现高频请求的问题。

如果不做任何处理,就会出现两个核心问题:

  • 执行次数过多:如果用户输入速度快,会在短时间内多次触发网络请求,网络次数过多,不仅服务器压力大,也会浪费前端性能。
  • 用户体验失衡:请求过快,频繁发送请求可能会导致响应混乱、页面卡顿;请求过慢,会导致联想建议延迟,影响使用体验

类似的场景还有很多,页面滚动加载、按钮重复提交,这些高频触发事件,都要通过防抖或节流来优化,避免“性能浪费”

这一切的实现,都离不开闭包的支持,利用闭包保留定时器ID,上一次执行时间等状态,让函数能够记住之前的执行状态,从而实现精准的触发控制,这就是防抖节流的核心底层逻辑。

防抖(Debounce): 多次触发,只执行最后一次

什么是防抖

防抖的核心逻辑:**在规定时间内,无论事件触发多少次,都只执行最后一次回调。**触发高频事件之后,函数不会立即执行,而是等待一段时间(延迟时间)后再执行;若在这段时间内事件再次被触发,则重新计时,只有当事件停止触发并且超过要延迟时间,函数才会执行一次。

防抖实现关键

/**
 * 防抖函数
 * @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):每隔一段时间,只执行一次

什么是节流

节流的核心逻辑:**在规定时间内,无论事件触发多少次,都只执行一次回调。**触发高频事件,限制函数在指定时间间隔内只执行一次,无论事件触发多少次,都会按照固定的频率执行函数。

节流实现关键

/**
 * 节流函数
 * @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)
核心逻辑等待最后一次触发后,延迟执行一次固定时间间隔内,只执行一次
执行时机事件停止触发后(延迟结束)事件触发过程中(按固定频率)
触发频率取决于事件停止触发的时间,可能很久执行一次固定频率执行,不受事件触发频率影响
核心目的过滤无效触发,保留最后一次结果控制执行频率,避免过度执行
通俗比喻电梯关门(有人进就重新计时)水龙头滴水(固定时间滴一滴)

总结

防抖和节流解决问题的核心目的是一致:优化高频事件的性能,避免复杂任务频繁执行,两者的核心区别在于防抖只执行最后一次,节流是固定时间间隔内只执行一次。在实际运用过程中,需要根据不同场景合理选择使用防抖或节流,提升页面性能,优化用户体验。