文章目录

JavaScript 性能优化:防抖与节流函数

发布于 2026-04-03 04:16:00 · 浏览 7 次 · 评论 0 条

JavaScript 性能优化:防抖与节流函数

网页中频繁触发的事件(如滚动、窗口缩放、输入搜索)会大量消耗浏览器资源,导致页面卡顿甚至崩溃。防抖(debounce)和节流(throttle)是两种经典解决方案,能有效控制函数执行频率,提升性能。


防抖:只在最后一次触发后执行

防抖的核心思想是:在指定时间间隔内,如果某事件被连续触发,则只在最后一次触发后的等待期结束后执行一次回调函数。适用于搜索框输入、窗口 resize 等场景。

实现防抖函数

编写一个通用的防抖函数:

function debounce(func, delay) {
  let timer = null;
  return function (...args) {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(this, args);
    }, delay);
  };
}
  • func 是你希望限制执行频率的目标函数。
  • delay 是等待时间(单位:毫秒),例如 300 表示 300 毫秒内无新触发才执行。
  • 函数返回一个新函数,该函数内部维护一个定时器 timer
  • 每次调用返回的函数时,先清除旧定时器,再设置新定时器。
  • 只有当连续两次调用间隔超过 delay 时,func 才会被真正执行。

使用防抖优化搜索框

假设有一个实时搜索功能,用户每输入一个字符就向服务器请求结果:

<input type="text" id="searchInput" placeholder="请输入关键词">

绑定防抖后的处理函数:

const searchInput = document.getElementById('searchInput');

function handleSearch(query) {
  console.log('正在搜索:', query);
  // 此处可替换为实际的 API 调用
}

const debouncedSearch = debounce(handleSearch, 500);

searchInput.addEventListener('input', (e) => {
  debouncedSearch(e.target.value);
});

现在,用户快速输入“apple”时,handleSearch 不会在每个字母输入时都执行,而是在用户停止输入 500 毫秒后,仅执行一次并传入完整关键词 “apple”。


节流:固定时间间隔内最多执行一次

节流的核心思想是:无论事件触发多么频繁,在指定时间间隔内,回调函数最多只执行一次。适用于滚动加载、按钮点击、鼠标移动等场景。

实现节流函数

编写一个通用的节流函数(基于时间戳方式):

function throttle(func, delay) {
  let lastExecTime = 0;
  return function (...args) {
    const currentTime = Date.now();
    if (currentTime - lastExecTime >= delay) {
      func.apply(this, args);
      lastExecTime = currentTime;
    }
  };
}
  • lastExecTime 记录上一次函数实际执行的时间。
  • 每次调用返回的函数时,获取当前时间并与上次执行时间比较。
  • 只有间隔大于等于 delay 时,才执行 func 并更新 lastExecTime

注意:此实现保证了首次触发立即执行,但可能在结束时漏掉最后一次触发。若需确保末尾执行,可结合定时器实现“leading + trailing”模式,但基础场景通常无需如此复杂。

使用节流优化滚动事件

监听 scroll 事件常用于实现“滚动到底部加载更多”:

function onScroll() {
  const scrollTop = window.scrollY;
  const windowHeight = window.innerHeight;
  const documentHeight = document.documentElement.scrollHeight;

  if (scrollTop + windowHeight >= documentHeight - 100) {
    console.log('接近底部,准备加载更多...');
    // 此处可触发数据加载
  }
}

const throttledScroll = throttle(onScroll, 200);

window.addEventListener('scroll', throttledScroll);

即使用户快速滚动页面,onScroll最多每 200 毫秒执行一次,避免高频计算导致主线程阻塞。


防抖 vs 节流:如何选择?

场景 推荐策略 原因
搜索框输入、表单验证 防抖 用户意图是最终输入结果,中间过程无需响应
滚动事件、窗口 resize、鼠标移动 节流 需要持续响应,但必须限制频率以保流畅
按钮重复点击(如提交订单) 防抖节流 防止多次提交;通常用防抖更直观(点击后一段时间内禁用)

进阶:带取消功能的防抖

有时需要在特定条件下取消已安排的执行(例如组件卸载时):

function debounceWithCancel(func, delay) {
  let timer = null;
  const debounced = function (...args) {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(this, args);
    }, delay);
  };

  debounced.cancel = function () {
    if (timer) {
      clearTimeout(timer);
      timer = null;
    }
  };

  return debounced;
}

使用时可随时调用 cancel() 方法:

const debouncedSave = debounceWithCancel(saveData, 1000);

// 在适当时候(如离开页面前)
debouncedSave.cancel(); // 确保不会在后台意外保存

验证优化效果

打开浏览器开发者工具(按 F12),切换到 Performance 面板:

  1. 点击 录制按钮(●)。
  2. 操作 页面(如快速滚动或输入)。
  3. 停止 录制。
  4. 观察 Main 线程中的 Function Call 记录:
    • 未优化时,事件回调会密集出现。
    • 应用防抖/节流后,回调数量显著减少,帧率(FPS)更稳定。

通过这种方式,你能直观看到性能提升。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文