节流必须用闭包,因其需私有持久保存lastTime和timer状态以避免污染与干扰;时间戳版首次立即执行、适合滚动监听,定时器版延迟执行最后一次、适合输入搜索,增强版支持leading/trailing配置亦依赖闭包统一管理状态。

节流的核心是控制函数执行频率,而闭包是实现它的必要手段——必须在多次调用之间私有、持久地保存状态(比如上一次执行时间或定时器 ID),又不能让这些状态暴露或互相干扰。
为什么必须用闭包
节流需要两个关键状态:
- lastTime:记录上一次真正执行回调的时间戳,用于判断是否已过间隔期
-
timer:保存
setTimeout返回的 ID,用于清除待执行的延迟任务
这两个值每次调用都不能重置,也不能被外部修改。闭包天然满足:外层函数定义变量,内层返回函数“记住”它们,形成独立作用域。不用闭包,就只能靠全局变量或对象属性,会导致多实例覆盖、竞态问题,甚至组件卸载后状态残留。
时间戳版:首次立即执行,适合滚动监听
逻辑是:首次触发立刻执行,之后在 delay 内的调用全部忽略,直到间隔过去才再次响应。它不依赖定时器,无延时偏差,适合 scroll、resize 等需稳定节奏的高频事件。
- 每次调用都比对
Date.now() - lastTime >= delay - 满足条件才执行回调,并更新
lastTime - 无定时器开销,响应更直接
定时器版:延迟执行最后一次,适合输入搜索
逻辑是:首次触发设一个延时任务,delay 后执行;期间重复触发会清除旧定时器、重设新的,最终只执行最后一次。适合搜索框输入后发请求、滚动到底部加载更多等场景。
- 必须用
clearTimeout清除已有timer -
timer要在闭包中声明并复用,不能每次新建 - 执行回调后记得清空
timer,避免状态滞留
增强版:支持 leading / trailing 配置
实际业务常需灵活控制“第一次是否立即执行”(leading)和“最后一次是否补发”(trailing)。这类逻辑必须由闭包统一管理状态——lastTime、timer、pending 标志位都需私有隔离,否则配置项与执行状态会错乱。
- leading 为 true 时,首次调用立刻执行并记录
lastTime - trailing 为 true 时,需在定时器回调中判断是否应补发(即上次执行后是否还有未处理调用)
- 所有开关和中间状态都在同一闭包内闭环维护,不泄露、不污染

















