节流是resize事件的必需方案,因其持续变化特性需稳定输出中间态;推荐100ms延迟以平衡性能与体验;需用支持leading/trailing及this绑定的节流函数,并注意移除监听、兼容orientationchange、优先使用matchMedia。

窗口 resize 事件在拖拽调整大小或设备旋转时会密集触发,直接响应会导致重排重绘堆积、图表尺寸错乱、内存泄漏等实际问题。节流不是“降频妥协”,而是用可控节奏维持关键状态更新——比如每 100ms 同步一次 canvas 宽高、刷新栅格列数、重设 SVG viewBox,既不卡顿,也不丢帧。
为什么必须用节流,而不是防抖
resize 是持续性变化过程,不是“操作结束才需要响应”的类型。例如:用户从桌面宽度缓慢拖窄到移动端断点,中间可能经过多个临界尺寸;若用防抖,只在松手后执行一次,就错过了导航栏折叠、侧边栏隐藏、字体缩放等逐级适配逻辑。节流则能稳定输出中间态,让 UI 变化更平滑自然。
选对延迟值:100ms 是实用平衡点
- 16ms(≈60fps)适合动画级响应,如实时拖拽预览、滚动跟随的尺寸联动,但对 CPU 压力明显增大
- 100ms是多数场景推荐值:人眼几乎无法感知延迟,且将每秒调用从数百次压至约 10 次,大幅降低布局计算压力
- 低于 50ms 需谨慎,尤其在低端 Android 或旧版 iOS WebKit 中,可能因 JS 执行阻塞导致视觉卡顿
写一个真正可用的节流函数
别只抄基础时间戳版——它不支持 leading(首次立即执行)和 this 绑定,在真实事件回调中容易出错:
复制即可用function throttle(fn, delay, options = {}) {<br> const { leading = true, trailing = true } = options;<br> let lastTime = 0;<br> let timeout = null;<br><br> return function(...args) {<br> const now = Date.now();<br> const passed = now - lastTime;<br><br> if (leading && !lastTime) {<br> fn.apply(this, args);<br> lastTime = now;<br> return;<br> }<br><br> if (passed >= delay) {<br> fn.apply(this, args);<br> lastTime = now;<br> } else if (trailing && !timeout) {<br> timeout = setTimeout(() => {<br> fn.apply(this, args);<br> lastTime = Date.now();<br> timeout = null;<br> }, delay - passed);<br> }<br> };<br>}
上线前必须检查的三件事
-
监听器要手动移除:页面卸载或组件销毁时,务必调用
window.removeEventListener('resize', handler),否则闭包引用 window 对象会造成内存泄漏 -
兼容 orientationchange:部分 iOS Safari 在横竖屏切换时不触发 resize,需额外监听
window.orientationchange并复用同一节流 handler -
优先用 matchMedia 替代 JS 判断断点:如果只是根据屏幕宽度切换 class 或显示隐藏模块,用
matchMedia('(max-width: 768px)')+ addListener 更轻量、更精准,避免无意义的尺寸计算


















