防抖和节流
防抖(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);
}
};
}
五、总结
- 选防抖还是节流?
- 需要避免重复触发(如搜索)→ 防抖。
- 需要固定频率执行(如滚动)→ 节流。
- 记忆技巧:
- 防抖:“等你不闹了再理你”(停止触发后执行)。
- 节流:“按点上班,其他时间休息”(固定频率执行)。
通过合理使用防抖和节流,可以显著提升高频事件处理的性能,避免不必要的计算和请求。