一、概念与区别
-
防抖(Debounce):
- 频繁触发时只在最后一次触发后执行
- 原理:每次触发都
clearTimeout重置定时器
-
节流(Throttle):
- 固定时间间隔内最多执行一次
- 原理:基于“比较时间”或“占位计时器”
二、最简实现
- 防抖(尾部执行)
function debounce(fn, wait = 300) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), wait);
};
}
- 节流(时间戳版:leading,可能丢尾)
function throttle(fn, wait = 300) {
let last = 0;
return function (...args) {
const now = Date.now();
if (now - last >= wait) {
last = now;
fn.apply(this, args);
}
};
}
- 节流(定时器版:trailing,不立即)
function throttle(fn, wait = 300) {
let timer = null;
return function (...args) {
if (timer) return;
timer = setTimeout(() => {
timer = null;
fn.apply(this, args);
}, wait);
};
}
三、进阶(可选项)
- 防抖(支持 leading/trailing)
function debounce(fn, wait = 300, { leading = false, trailing = true } = {}) {
let timer = null, lastArgs, lastThis;
const invoke = () => {
timer = null;
if (trailing && lastArgs) {
fn.apply(lastThis, lastArgs);
lastArgs = lastThis = null;
}
};
const debounced = function (...args) {
lastArgs = args; lastThis = this;
const callNow = leading && !timer;
clearTimeout(timer);
timer = setTimeout(invoke, wait);
if (callNow) { fn.apply(lastThis, lastArgs); lastArgs = lastThis = null; }
};
debounced.cancel = () => { clearTimeout(timer); timer = null; lastArgs = lastThis = null; };
debounced.flush = () => { if (timer) { clearTimeout(timer); invoke(); } };
return debounced;
}
- 节流(同时支持 leading/trailing)
function throttle(fn, wait = 300, { leading = true, trailing = true } = {}) {
let last = 0, timer = null, lastArgs, lastThis;
const invoke = (time) => { last = time; fn.apply(lastThis, lastArgs); lastArgs = lastThis = null; };
return function (...args) {
const now = Date.now();
if (!last && leading === false) last = now;
const remaining = wait - (now - last);
lastArgs = args; lastThis = this;
if (remaining <= 0) {
if (timer) { clearTimeout(timer); timer = null; }
invoke(now);
} else if (!timer && trailing !== false) {
timer = setTimeout(() => { timer = null; invoke(leading === false ? Date.now() : last + wait); }, remaining);
}
};
}