给我解释下 前端开发中的防抖和节流 并举个具体的例子
防抖(Debounce)与节流(Throttle)详解
在前端开发中,防抖(Debounce) 和 节流(Throttle) 是两种优化高频触发事件的技术,用于提升性能和用户体验。它们的核心区别在于:
- 防抖:将多次触发合并为一次执行(只执行最后一次)。
- 节流:限制事件执行频率(按固定间隔执行)。
防抖(Debounce)
原理
- 在事件被触发后,延迟
n
毫秒再执行回调。 - 如果在这
n
毫秒内再次触发事件,则重新计时。
适用场景
- 搜索框实时联想(用户停止输入后再请求)。
- 窗口 resize 事件(只在调整结束后计算布局)。
- 按钮提交防止重复点击。
代码示例
javascript
// 防抖函数(非立即执行版)
function debounce(fn, delay) {
let timer = null;
return function(...args) {
// 清除上一次定时器
if (timer) clearTimeout(timer);
// 重新设置定时器,延迟执行
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
// 使用示例
const searchInput = document.getElementById('search-input');
searchInput.addEventListener('input', debounce((e) => {
console.log('搜索:', e.target.value);
// 发送搜索请求...
}, 300));
节流(Throttle)
原理
- 限制一个函数在一定时间内只能执行一次。
- 即使在这段时间内多次触发事件,也只会按固定间隔执行。
适用场景
- 滚动加载更多数据(每滚动一定距离触发一次)。
- 高频点击按钮(如点赞、提交)。
- 游戏中的技能冷却。
代码示例
javascript
// 节流函数(时间戳版)
function throttle(fn, limit) {
let lastExecTime = 0;
return function(...args) {
const now = Date.now();
// 如果距离上次执行超过限制时间,则执行
if (now - lastExecTime > limit) {
fn.apply(this, args);
lastExecTime = now;
}
};
}
// 使用示例
window.addEventListener('scroll', throttle(() => {
console.log('滚动位置:', window.scrollY);
// 检查是否需要加载更多数据...
}, 200));
对比与选择
特性 | 防抖(Debounce) | 节流(Throttle) |
---|---|---|
执行时机 | 只在最后一次事件触发后执行 | 按固定间隔执行 |
高频触发 | 只执行一次 | 按频率执行多次 |
应用场景 | 搜索联想、窗口 resize、防止重复提交 | 滚动加载、高频点击、游戏技能冷却 |
实现方式 | 定时器 | 时间戳或定时器 |
高级实现(带配置选项)
防抖(支持立即执行)
javascript
function debounce(func, wait, immediate = false) {
let timeout;
return function() {
const context = this;
const args = arguments;
const later = () => {
timeout = null;
if (!immediate) func.apply(context, args);
};
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
节流(结合时间戳和定时器)
javascript
function throttle(func, limit) {
let timeout;
let lastExecTime = 0;
return function() {
const context = this;
const args = arguments;
const now = Date.now();
const remaining = limit - (now - lastExecTime);
if (remaining <= 0) {
// 如果超过限制时间,立即执行
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
func.apply(context, args);
lastExecTime = now;
} else if (!timeout) {
// 否则,等待剩余时间后执行
timeout = setTimeout(() => {
func.apply(context, args);
lastExecTime = Date.now();
timeout = null;
}, remaining);
}
};
}
实际应用示例
1. 搜索框防抖
javascript
const searchInput = document.getElementById('search-input');
searchInput.addEventListener('input', debounce((e) => {
// 300ms 内没有新输入时才发送请求
fetch(`/api/search?q=${e.target.value}`)
.then(res => res.json())
.then(data => renderResults(data));
}, 300));
2. 滚动加载节流
javascript
window.addEventListener('scroll', throttle(() => {
// 每 200ms 检查一次是否需要加载更多
if (isScrollAtBottom()) {
loadMoreData();
}
}, 200));
3. 按钮点击防抖
javascript
const submitBtn = document.getElementById('submit-btn');
submitBtn.addEventListener('click', debounce(() => {
// 防止重复提交,2秒内只执行一次
submitForm();
}, 2000, true)); // 立即执行版,点击后先执行,2秒内不再执行
总结
- 防抖:适合需要合并多次触发的场景,避免不必要的计算或请求。
- 节流:适合需要限制执行频率的场景,如滚动、拖拽等高频事件。
合理使用这两种技术可以显著提升应用性能,减少资源浪费,改善用户体验