防抖是“等停了再执行”,节流是“固定节奏执行”;防抖适用于只关心最终结果的场景(如搜索输入),节流适用于需持续反馈但限频的场景(如滚动监听)。

防抖和节流都是用来控制函数执行频率的技术,核心区别在于:防抖是“等停了再执行”,节流是“固定节奏执行”。选哪个,关键看用户操作的意图是否需要被完整响应。
防抖(Debounce):适合“只关心最终结果”的场景
防抖会让函数在最后一次触发后,等待指定时间无新触发才执行。中间所有调用都被忽略。
- 典型应用:搜索框输入联想、窗口大小调整(resize)、表单输入校验
- 原因:用户快速打字时,你不需要为每个字符都发请求;等他停顿下来(比如 300ms 内没再输),再查一次最合适的关键词即可
- 简单实现:
function debounce(fn, delay) {
let timer = null;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
注意:每次新调用都会重置倒计时,且 this 和参数需正确传递(用 apply 或箭头函数绑定)。
节流(Throttle):适合“需要持续反馈但不能太频繁”的场景
节流保证函数在指定时间间隔内最多执行一次,即使触发多次,也按固定节奏执行(如每 100ms 最多跑一次)。
立即学习“Java免费学习笔记(深入)”;
- 典型应用:鼠标拖拽、滚动监听(scroll)、Canvas 绘图、游戏中的按键响应
- 原因:滚动页面时,你可能需要实时更新吸顶导航或懒加载图片,但浏览器每秒触发几十次 scroll 事件,全响应会卡顿,节流能兼顾流畅与性能
- 两种常见实现方式:定时器版(推荐)和时间戳版
// 定时器版(更稳定,确保至少执行一次)
function throttle(fn, delay) {
let timer = null;
return function(...args) {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, args);
timer = null;
}, delay);
}
};
}
怎么选?看三个问题
- 用户操作是“连续动作”还是“离散终点”?—— 拖拽是连续,搜索提交是终点 → 节流 vs 防抖
- 是否允许丢弃中间状态?—— 图片懒加载可以等滚动停下再算,但拖拽位置必须实时反映 → 节流更合适
- 有没有“首次立即执行”的需求?—— 比如下拉刷新希望一拉就响应,之后再节流 → 可扩展节流函数加 leading 参数
小提醒:别滥用,也别手写轮子
现代项目中,Lodash 的 debounce 和 throttle 已经处理好 this、参数、取消、立即执行等细节,建议直接用。自己实现主要用于理解原理或极简环境。另外,像 resize 或 scroll 这类高频事件,加上防抖/节流几乎是标配,不加很可能引发性能问题。










