防抖函数是处理resize等高频事件的有效方式,确保回调在用户停止调整窗口后延迟执行一次,避免卡顿、内存泄漏和尺寸读取错误。

防抖函数是处理窗口大小改变(resize)这类高频事件最常用且有效的方式——它能确保回调只在用户停止调整窗口后的指定延迟后执行一次,避免连续重绘、重复计算布局或触发不必要的 API 调用。
为什么 resize 事件需要防抖
浏览器在拖拽窗口边缘时,resize 事件可能每秒触发数十次。若直接绑定 DOM 操作、计算元素尺寸或触发响应式逻辑,会导致:
- 页面卡顿(频繁重排重绘)
- 内存泄漏(未清理的定时器或闭包引用)
- 错误的尺寸读取(如在动画中间获取 offsetWidth,值不准确)
一个可靠的手写防抖函数
关键点:清除上一次定时器、保留 this 和参数、支持立即执行选项(可选):
function debounce(func, wait, immediate = false) {
let timeout;
return function(...args) {
const later = () => {
timeout = null;
if (!immediate) func.apply(this, args);
};
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(this, args);
};
}
使用示例:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
const handleResize = debounce(() => {
console.log('窗口尺寸已稳定', window.innerWidth, window.innerHeight);
// 更新图表、重排网格、调整 canvas 大小等
}, 250);
window.addEventListener('resize', handleResize);
更现代的写法:用 AbortController 清理(推荐用于复杂场景)
如果防抖逻辑嵌套在组件中(如 React、Vue),或需配合异步操作(如 resize 后 fetch 数据),建议用 AbortController 显式控制生命周期:
function debounceAsync(fn, delay) {
let controller;
return async function(...args) {
controller?.abort();
controller = new AbortController();
try {
await new Promise(resolve => {
setTimeout(() => resolve(), delay);
}, { signal: controller.signal });
fn.apply(this, args);
} catch (e) {
if (e.name !== 'AbortError') throw e;
}
};
}
这样可在组件卸载时调用 controller.abort(),彻底避免内存泄漏和过期回调执行。
实际开发中的注意事项
- 延迟时间别太短:200–300ms 是较平衡的选择;低于 100ms 仍可能触发多次,高于 500ms 用户会感知延迟
-
避免在防抖函数里直接操作 DOM 样式:优先用 CSS 媒体查询或
matchMedia处理纯样式响应 -
考虑 resizeObserver 替代方案:如果只关心某个容器尺寸变化(而非整个窗口),
ResizeObserver更精准、性能更好,且天然防抖 -
移动端注意 orientationchange:Safari 在横竖屏切换时可能不触发 resize,需额外监听
orientationchange并合并处理

















