Skip to main content

防抖和节流

防抖(Debounce)和节流(Throttle)是前端优化高频事件(如滚动、点击、输入框搜索)的两种常见技术,用于限制函数执行频率,提升性能。以下是核心概念、应用场景及代码实现:

一、防抖(Debounce)

概念

  • 触发规则:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
  • 特点:只执行最后一次触发,适合避免重复操作(如搜索联想、窗口调整)。

应用场景

  • 搜索框输入联想(用户停止输入后再请求)。
  • 窗口大小调整(resize事件)。
  • 按钮重复提交(如点赞、支付)。

代码实现

function debounce(fn, delay) {
let timer = null;
return function() {
const context = this;
const args = arguments;
// 清除上一次定时器
clearTimeout(timer);
// 重新计时
timer = setTimeout(() => {
fn.apply(context, args);
}, delay);
};
}

// 使用示例
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', debounce((e) => {
console.log('搜索内容:', e.target.value);
// 发起搜索请求
}, 300));

二、节流(Throttle)

概念

  • 触发规则:在一定时间间隔内,只执行一次函数。
  • 特点:固定频率执行,适合限制频繁触发(如滚动加载、按钮点击)。

应用场景

  • 滚动加载更多(如微博、朋友圈)。
  • 高频点击(如点赞、抢购按钮)。
  • 游戏中的角色移动控制。

代码实现(时间戳版)

function throttle(fn, delay) {
let lastTime = 0;
return function() {
const context = this;
const args = arguments;
const now = Date.now();
// 判断是否达到执行时间
if (now - lastTime > delay) {
fn.apply(context, args);
lastTime = now;
}
};
}

// 使用示例
window.addEventListener('scroll', throttle(() => {
console.log('滚动位置:', window.scrollY);
// 判断是否需要加载更多
}, 500));

三、核心区别

特性防抖(Debounce)节流(Throttle)
执行时机只执行最后一次触发固定间隔执行一次
应用场景避免重复操作(如搜索联想)限制频繁触发(如滚动加载)
实现关键清除并重置定时器判断时间间隔是否达到阈值

四、高级实现(可选)

防抖升级版(立即执行+取消功能)

function debounce(fn, delay, immediate = false) {
let timer = null;
let result;
const debounced = function() {
const context = this;
const args = arguments;
if (timer) clearTimeout(timer);

if (immediate) {
// 立即执行逻辑
const callNow = !timer;
timer = setTimeout(() => {
timer = null;
}, delay);
if (callNow) result = fn.apply(context, args);
} else {
// 非立即执行逻辑
timer = setTimeout(() => {
fn.apply(context, args);
}, delay);
}
return result;
};

// 添加取消功能
debounced.cancel = function() {
clearTimeout(timer);
timer = null;
};

return debounced;
}

节流升级版(时间戳+定时器结合)

function throttle(fn, delay) {
let timer = null;
let lastTime = 0;

return function() {
const context = this;
const args = arguments;
const now = Date.now();
const remaining = delay - (now - lastTime);

// 剩余时间小于等于0,表示上次执行已过delay
if (remaining <= 0 || remaining > delay) {
if (timer) {
clearTimeout(timer);
timer = null;
}
fn.apply(context, args);
lastTime = now;
} else if (!timer) {
// 保证最后一次触发能执行
timer = setTimeout(() => {
fn.apply(context, args);
lastTime = Date.now();
timer = null;
}, remaining);
}
};
}

五、总结

  • 选防抖还是节流?
    • 需要避免重复触发(如搜索)→ 防抖
    • 需要固定频率执行(如滚动)→ 节流
  • 记忆技巧
    • 防抖:“等你不闹了再理你”(停止触发后执行)。
    • 节流:“按点上班,其他时间休息”(固定频率执行)。

通过合理使用防抖和节流,可以显著提升高频事件处理的性能,避免不必要的计算和请求。