| 特性 | 防抖(Debounce) | 节流(Throttle) |
|---|---|---|
| 核心思想 | "等你说完我再响应" | "按固定节奏响应" |
| 触发策略 | 延迟执行,期间新触发会重置计时 | 固定时间间隔内只执行一次 |
| 类比场景 | 电梯门(最后一个人进后关门) | 机枪扫射(按固定频率发射) |
| 典型应用 | 搜索联想、窗口 resize 结束监听 | 滚动加载、高频点击按钮 |
function debounce(func, delay) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}/**
* 防抖函数
* @param {Function} fn - 目标函数
* @param {number} delay - 延迟时间(ms)
* @param {boolean} immediate - 是否立即执行
* @returns {Function} 防抖处理后的函数
*/
function debounce(fn, delay = 300, immediate = false) {
let timer = null;
return function(...args) {
const context = this;
// 清除已有定时器
if (timer) clearTimeout(timer);
// 立即执行模式
if (immediate && !timer) {
fn.apply(context, args);
}
timer = setTimeout(() => {
timer = null;
if (!immediate) {
fn.apply(context, args);
}
}, delay);
};
}function throttle(func, delay) {
let lastTime = 0;
return function(...args) {
const now = new Date().getTime();
if (now - lastTime >= delay) {
func.apply(this, args);
lastTime = now;
}
};
}/**
* 节流函数
* @param {Function} fn - 目标函数
* @param {number} interval - 时间间隔(ms)
* @param {boolean} trailing - 是否在间隔末尾执行
* @returns {Function} 节流处理后的函数
*/
function throttle(fn, interval = 300, trailing = true) {
let lastTime = 0;
let timer = null;
return function(...args) {
const context = this;
const now = Date.now();
// 时间差计算
const remaining = interval - (now - lastTime);
if (remaining <= 0) {
// 到达间隔时间立即执行
if (timer) {
clearTimeout(timer);
timer = null;
}
fn.apply(context, args);
lastTime = now;
} else if (trailing && !timer) {
// 间隔末尾补发执行
timer = setTimeout(() => {
fn.apply(context, args);
lastTime = Date.now();
timer = null;
}, remaining);
}
};
}// 防抖应用:搜索框联想
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', debounce(function(e) {
console.log('搜索关键词:', e.target.value);
}, 500));
// 节流应用:滚动加载
window.addEventListener('scroll', throttle(function() {
console.log('当前滚动位置:', window.scrollY);
}, 1000));| 功能 | 防抖实现要点 | 节流实现要点 |
|---|---|---|
| 定时器管理 | 每次触发重置定时器 | 通过时间戳判断间隔,定时器用于补发执行 |
| 上下文绑定 | 使用 apply 保持 this 指向正确 |
同上 |
| 参数传递 | ...args 保留所有原始参数 |
同上 |
| 边缘情况处理 | 处理立即执行模式 | 处理首尾触发模式 |
-
取消功能
// 防抖增加取消方法 function debounce(...) { const debounced = function(...args) { ... }; debounced.cancel = () => { clearTimeout(timer); timer = null; }; return debounced; }
-
返回值处理
(注:异步函数无法直接返回结果,可通过回调或 Promise 处理) -
RAF 节流
// 使用 requestAnimationFrame 实现动画节流 function throttleRAF(fn) { let ticking = false; return function(...args) { if (!ticking) { requestAnimationFrame(() => { fn.apply(this, args); ticking = false; }); ticking = true; } }; }
- 防抖:高频事件结束后触发,避免重复执行(如输入验证)
- 节流:高频事件按节奏触发,保障最低执行频率(如滚动计算)
- 生产建议:直接使用 Lodash 的
_.debounce和_.throttle(已处理大量边界情况)