节流函数需同时使用时间戳和定时器:时间戳判断是否立即执行并更新上次执行时间,定时器兜底确保最后一次触发不被遗漏;二者缺一不可,仅用定时器是防抖而非节流。

节流函数中结合时间戳与定时器,核心在于用时间戳记录上次执行时间、用定时器兜底保证最后一次触发不被丢弃——两者配合才能实现“高频触发、低频执行”且“结尾补发”的精准控制。
时间戳负责判断是否该立即执行
每次触发时,先获取当前时间戳,减去上次执行的时间戳,若间隔超过设定阈值(如 100ms),就立刻执行函数,并更新“上次执行时间”。这种方式响应快、无延迟,但缺点是:如果用户持续快速触发,最后一次松手时可能刚好错过阈值判断,导致本该执行的尾部调用被跳过。
示例逻辑:
- 记录 lastTime = 0
- 触发时取 now = Date.now()
- 若 now - lastTime >= delay,则执行函数并更新 lastTime = now
定时器负责兜底执行遗漏的最后一次
仅靠时间戳会漏掉结尾。解决办法是:每次触发时,先清除旧定时器,再设置一个延迟为 delay 的新定时器。当定时器到期时,检查距离上一次真正执行是否已超时——如果是,就执行;否则不执行(避免重复)。这要求把“上次执行时间”和“定时器 ID”都维护在闭包中。
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
关键点:
- 定时器只做“延迟尝试”,不保证一定执行
- 定时器回调里需再次比对时间戳,确保不是因抖动提前触发
- 必须清除前一个定时器,防止多个定时器并发执行
组合策略:时间戳主控 + 定时器兜底
真正健壮的节流,是把两种方式融合:时间戳决定“能否立刻干”,定时器负责“万一没干,稍后补上”。典型实现如下:
- 初始化 lastTime = 0 和 timer = null
- 触发时:先清定时器,再计算 remaining = delay - (Date.now() - lastTime)
- 若 remaining ,立即执行并更新 lastTime
- 否则,设 setTimeout(() => { 执行并更新 lastTime }, remaining)
这样既避免了固定 delay 的呆板等待,又确保了结尾必有一次执行,响应更贴近用户意图。
注意防抖与节流别混用
有人误把“定时器清空+重设”当成节流,其实那是防抖。节流的关键特征是:单位时间内至少执行一次,且允许结尾补一次。如果代码里只有 clearTimeout 和 setTimeout,没维护和比对时间戳,那只是防抖。真节流必须同时持有“最近执行时间”和“待执行定时器”两个状态。

















