防抖是用户停止触发后延迟执行,节流是固定间隔最多执行一次;错误混用会导致响应异常;推荐闭包封装避免全局污染,并支持立即执行、取消及时间戳精准控制。

防抖和节流的核心区别要先理清
防抖(Debounce)是等用户“停手”后再执行,比如搜索框输入完 300ms 再发请求;节流(Throttle)是固定频率执行,比如滚动事件每 100ms 最多触发一次。写错逻辑会导致行为反直觉——把节流当防抖用,可能连续点击只响应第一次;把防抖当节流用,可能滚动中完全不触发回调。
用闭包封装,避免全局变量污染
老式写法常把 timer ID 挂在全局或 this 上,容易冲突、难测试。推荐用闭包隔离状态:
✅ 推荐写法(防抖):
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
❌ 避免写法:
把 timer 放在函数外、或用 this.timer(绑定不牢时会失效)。
支持立即执行 + 取消能力,才算完整
真实场景需要更精细控制:比如按钮点击希望立刻响应,但后续连续点击要忽略;又或者组件卸载时主动取消待执行任务。重构时建议加两个可选参数:
使用约定式提交(Conventional Commits)生成标准化的 Git 提交信息。适用于以下场景: (1) 暂存更改时需要提交信息; (2) 审查 diff 时希望获得结构化摘要; (3) 编写 PR 描述或变更日志(changelog)条目; (4) 用户明确要求“为本次更改编写提交信息”。 该功能会分析已暂存/未暂存的 diff,并生成按类型(type)划分范围的提交信息。
- immediate:true 表示首次调用立即执行,后续在 wait 期内不执行
- cancel 方法:返回一个可调用的取消函数,用于清理
节流同理,可增加 leading(开头触发)和 trailing(结尾触发)开关,默认都开,按需关闭。
用 requestIdleCallback 或时间戳优化节流精度
单纯用 setTimeout 节流在高负载下可能不准。更健壮的做法是记录上一次执行时间,每次调用时比对是否超间隔:
function throttle(fn, delay) {
let last = 0;
return function (...args) {
const now = Date.now();
if (now - last >= delay) {
fn.apply(this, args);
last = now;
}
};
}
对非关键渲染任务(如日志上报),还可结合 requestIdleCallback 延迟到浏览器空闲时执行,减少卡顿。










