防抖函数在 window.resize 场景下核心作用是将高频触发收拢为一次执行,避免布局重排与主线程阻塞;因其是同步事件且易引发强制回流,需合理设延迟、隔离闭包、正确绑定 this,并配合手动卸载监听器以防内存泄漏。

防抖函数在 window.resize 场景下,核心作用是把高频、密集的触发“收拢”成一次执行,避免因浏览器每秒触发 40–80 次 resize 而导致布局重排(layout thrashing)、主线程阻塞甚至卡顿。
为什么 resize 特别需要防抖
resize 是操作系统级同步事件,不走事件循环队列,无法被节流或取消。每次触发若伴随 DOM 读写(比如获取 offsetHeight 后立刻设置 style.width),就会强制触发同步回流——单次耗时可达 15–30ms。连续触发几十次,等于让主线程持续满载,动画掉帧、交互延迟就不可避免。
防抖实现的关键细节
一个可用的防抖函数不只是套个 setTimeout,还要注意三点:
-
闭包变量隔离:每个防抖实例应维护独立的
timer,避免多个监听器互相干扰 -
this 和参数传递:用
func.call(this, ...args)保证上下文和实参正确,尤其在 class 方法或 Vue 实例中 - 延迟时间取值合理:250ms 是常见平衡点——足够覆盖用户拖拽停顿,又不会造成明显响应延迟;对纯布局调整可设为 150ms,对需上报尺寸的场景建议 ≥300ms
实际使用中的避坑提醒
防抖不是加了就万事大吉,还需配合生命周期管理:
-
必须手动卸载监听器:尤其在单页应用(如 Vue/React)组件销毁时,漏掉
removeEventListener会导致闭包持有组件实例,引发内存泄漏 -
避免在防抖函数内直接操作 DOM 样式:优先用 CSS 媒体查询或
matchMedia处理响应式切换;防抖更适合做尺寸计算、状态更新或 API 上报等非渲染任务 - 不要和 requestAnimationFrame 混用:raf 本身已按帧调度,再套防抖反而可能错失关键渲染时机;如需精确对齐帧,应改用节流 + raf 组合
一个轻量可靠的防抖封装示例
以下代码可直接复用,兼顾兼容性与健壮性:
function debounce(fn, delay = 250) {
let timer = null;
return function (...args) {
const context = this;
clearTimeout(timer);
timer = setTimeout(() => fn.apply(context, args), delay);
};
}
// 使用
const handleResize = debounce(() => {
const width = window.innerWidth;
// 仅做计算或状态更新,不直接写 style
updateLayoutState(width);
}, 250);
window.addEventListener('resize', handleResize);
// 卸载时(例如组件 unmounted)
// window.removeEventListener('resize', handleResize);


















