节流函数的核心作用是将高频事件“匀速化”,即每过固定时间最多执行一次,适用于滚动加载、实时计算可视区域等需持续感知变化的场景;其与防抖的本质区别在于节流保留中间态、防抖只响应终态;标准实现需控制leading(首次立即执行)、trailing(末次补调),并配合passive: true避免主线程阻塞。

节流函数的核心作用,是把高频触发的事件“匀速化”——不是等用户停手再执行(那是防抖),而是保证每过固定时间最多执行一次。滚动、缩放、鼠标移动这类事件动辄每秒几十上百次,不加节流,轻则卡顿,重则页面无响应。
节流和防抖的根本区别
节流像地铁闸机:刷卡进站后,2秒内别人刷不了,但2秒一到,下一个人立刻能刷;防抖像电梯关门:每次有人进来,倒计时就重置,必须彻底没人了才关门。所以:
- 滚动加载更多、实时计算可视区域元素,适合用节流——需要持续感知变化
- 搜索框联想、窗口尺寸校准,更适合防抖——只关心最终稳定状态
- 节流保留中间态,防抖只响应终态
标准节流实现的关键控制点
一个健壮的节流函数不能只靠 setTimeout 或时间戳单点判断,得兼顾首次、末次、this 绑定和事件对象有效性:
- leading 控制是否立即执行第一次调用。设为 true,滚动一开始就能触发处理逻辑
- trailing 控制是否在最后一次触发后补调一次。设为 true,可避免因快速滚动结束而漏掉临界位置的判断
- 滚动事件对象是复用的,节流回调里直接用 event 可能拿到过期数据,应优先用
event.target.scrollTop或window.scrollY这类即时值 - 务必配合
{ passive: true }使用 addEventListener,否则浏览器会强制同步执行你的回调,节流再好也白搭
实际使用中的常见配置建议
不同场景对“节奏感”要求不同,别死守一个 wait 值:
- 滚动监听做懒加载或吸顶效果:用
throttle(fn, 16, { leading: true, trailing: true })—— 16ms ≈ 60fps,视觉最顺滑 - 拖拽过程中实时更新位置预览:用
throttle(fn, 50),降低计算压力,人眼几乎无感延迟 - resize 监听布局变化:
throttle(fn, 200)足够,毕竟窗口不会每秒拉伸5次 - 避免把节流函数反复绑定,每次绑定前先用
removeEventListener清理,或用同一个闭包实例
别忽略的底层性能开关:passive
现代浏览器对未声明 passive: true 的 scroll/resize 监听器,默认认为你可能要调用 preventDefault(),于是强制同步执行回调,直接阻塞主线程滚动。哪怕节流函数里只写了一行 console.log,也会让滚动卡顿。正确写法:
window.addEventListener('scroll', throttledScroll, { passive: true });
这是比节流更前置、更关键的一层优化,漏掉它,节流效果大打折扣。

















