前端总说的防抖与节流到底是什么?

一、 一句话说明白

  • 防抖 是"等一等",等到最后一次操作才执行。
  • 节流 是"省一省",不管多快,都按固定频率执行。

二、 防抖 (Debounce)

防抖的原理是:在事件被触发 n 秒后再执行回调,如果在这 n 秒内又被触发,则重新计时。

可以将防抖理解为"最后一次说了算"。

其核心在于延迟执行,只有当用户停止操作一段时间后,才真正执行逻辑。

以下是一个具备通用性的防抖函数实现,利用闭包保存定时器状态。

JavaScript 复制代码
/**
 * 防抖函数 (Debounce)
 * @param {Function} fn - 需要执行的函数
 * @param {Number} delay - 延迟时间 (毫秒)
 * @returns {Function} - 包装后的函数
 */
function debounce(fn, delay) {
  let timer = null;

  return function (...args) {
    // 如果此时再次触发,则清除上一次的定时器,重新计时
    if (timer) clearTimeout(timer);

    // 保存当前的 this 上下文,确保 fn 执行时 this 指向正确
    const context = this;

    timer = setTimeout(() => {
      fn.apply(context, args);
      timer = null;
    }, delay);
  };
}

// --- 使用示例 ---
const handleInput = debounce((e) => {
  console.log('搜索请求发送,关键词:', e.target.value);
}, 500);

// 绑定到输入框
// document.getElementById('search').addEventListener('input', handleInput);
  • 搜索框输入联想 (Input Search): 用户在不断输入字符时,不应立即请求后端接口,而是等待用户停止输入(如停顿 300ms)后再发送请求。
  • 窗口大小调整 (Window Resize): 只需要在窗口调整结束后计算一次布局,而非调整过程中不断计算。
  • 表单验证: 避免每输入一个字符就验证一次,而是输入完成后验证。

三、 节流 (Throttle)

节流的原理是:规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。

可以将节流理解为"按照固定的频率执行"。

无论事件触发得多么频繁,执行频率都是稀疏且固定的。

节流通常有两种实现方式:时间戳版 (立即执行)和定时器版(延后执行)。

以下推荐一种基于时间戳的高效实现,适合滚动等需要立即响应的场景。

JavaScript 复制代码
/**
 * 节流函数 (Throttle) - 时间戳版
 * @param {Function} fn - 需要执行的函数
 * @param {Number} interval - 间隔时间 (毫秒)
 * @returns {Function} - 包装后的函数
 */
function throttle(fn, interval) {
  let lastTime = 0;

  return function (...args) {
    const now = Date.now();
    
    // 如果当前时间与上次执行时间的差值大于设定间隔,则执行
    if (now - lastTime >= interval) {
      fn.apply(this, args); // 修正 this 指向并传递参数
      lastTime = now;
    }
  };
}

// --- 使用示例 ---
const handleScroll = throttle(() => {
  console.log('触发滚动检测', window.scrollY);
}, 200);

// 绑定到滚动事件
// window.addEventListener('scroll', handleScroll);
  • 页面滚动 (Scroll): 监听滚动条位置以实现"懒加载"或"吸顶"效果。不需要每像素移动都执行,每隔 100ms 检查一次即可。
  • DOM 元素拖拽 (Drag and Drop): 在拖拽过程中通过节流限制计算位置的频率,避免卡顿。
  • 高频点击提交: 防止用户疯狂点击按钮导致多次提交表单。

四、成熟的工具库

在实际的大型项目中,除非为了减少依赖体积或特定需求,通常不建议手写上述基础函数,因为需要处理更复杂的边界情况(如取消操作、立即执行选项等)。

  1. Lodash: 使用 _.debounce 和 _.throttle。

    • 例如:_.debounce(func, [wait=0], [options={}]) 支持 leading (前沿触发) 和 trailing (后沿触发) 配置。
  2. RequestAnimationFrame: 对于涉及动画或极高频的 UI 渲染(如拖拽),现代浏览器推荐使用 requestAnimationFrame 代替传统的定时器节流,以获得更流畅的视觉效果 (60FPS)。

相关推荐
小码哥_常4 小时前
一套自己部署的 IM,客户端是同一份 Flutter
前端·后端
蜗牛攻城狮6 小时前
微前端四大方案选型对比与最佳实践:qiankun、micro-app、wujie、Module Federation
前端·微前端·qiankun·前端架构·micro-app·wujie
她说可以呀7 小时前
Vue插槽
前端·javascript·vue.js
qq_448011167 小时前
Vue + Jinja2两套模版与法冲突造成undefinedError
前端·javascript·vue.js
aixingpan8 小时前
aixingpan.cn API开发文档:前端查询夏令时和时区接口指南
前端·php
Yuzhiyuxia8 小时前
【AI Agent面试系列】AI Agent记忆机制知识点1
人工智能·面试·职场和发展
2601_958352908 小时前
23.5×19mm 换掉一整条音频链?|A-68 集成了什么:ADC / DAC / 24.576MHz 时钟 / AEC / 波束降噪,主控仅需 6 根线
前端·音视频·ai降噪·回声消除·语音模块
志尊宝9 小时前
AI原生前端开发(039):AI辅助的Nuxt 4全栈开发
前端·vue.js·ai-native
FRing0310 小时前
JavaScript入门到精通三十二(深拷贝、浅拷贝、递归函数)
开发语言·前端·javascript
excel10 小时前
双 Token 与前端使用 Crypto 公私钥鉴权换 Token,哪种方案更好?
前端·后端