防抖与节流
1. 是什么?
本质上都是优化高频率执行代码的一种手段。
如浏览器的 resize、scroll、keypress、mousemove 等事件在触发时,会不断调用绑定在事件上的回调函数,极大地浪费资源、降低前端性能。
为了优化体验,需要对这类事件进行调用次数的限制,对此我们可以采用 throttle(节流) 和 debounce(防抖) 的方式来减少调用频率。
- 防抖(debounce):触发事件后 n 秒内不再触发才执行;若持续触发则一直延迟。常见场景:搜索框输入、按钮防重复提交、resize 后重绘。
- 节流(throttle):保证 n 秒内只执行一次。常见场景:滚动加载、动画帧、射击游戏中的子弹频率。
2. 实现
防抖(debounce)
function debounce(fn, wait) {
let timer = null;
return function (...args) {
const context = this;
clearTimeout(timer);
timer = setTimeout(() => fn.apply(context, args), wait);
};
}
节流(throttle)—— 时间戳版本
function throttle(fn, delay) {
let last = 0;
return function (...args) {
const now = Date.now();
if (now - last >= delay) {
last = now;
fn.apply(this, args);
}
};
}
节流(throttle)—— 定时器版本
function throttle(fn, delay) {
let timer = null;
return function (...args) {
if (!timer) {
timer = setTimeout(() => {
timer = null;
fn.apply(this, args);
}, delay);
}
};
}
精确节流:结合写法
function throttled(fn, delay) {
let timer = null;
let oldTime = Date.now();
return function (...args) {
const curTime = Date.now();
const remaining = delay - (curTime - oldTime);
const context = this;
clearTimeout(timer);
if (remaining <= 0) {
fn.apply(context, args);
oldTime = Date.now();
} else {
timer = setTimeout(() => fn.apply(context, args), remaining);
}
};
}
3. 使用场景
- 防抖:搜索联想、表单校验、按钮防重、resize 结束后的重绘。
- 节流:滚动加载、动画帧、滚动事件、拖拽场景、高频鼠标移动。
补充:注意区分:
lodash的debounce/throttle提供更多可选项(leading、trailing、maxWait)。- 现代前端也可以用
requestAnimationFrame来做"帧级节流",常用于滚动 / 动画场景。 - 千万不要把防抖和节流混用,行为差别很大。
来源整理自:我的有道云笔记



