函数节流核心是控制高频触发下函数执行频率,分定时器版(尾部延迟执行、首次不立即执行)和时间戳版(首调立即执行、后续按间隔节制),二者适用场景与性能表现各异。

函数节流(Throttle)的核心目标是控制函数执行频率,确保在高频触发(如滚动、拖拽、鼠标移动)时,函数按固定间隔执行,而不是每次触发都执行。定时器版和时间戳版是两种经典实现方式,逻辑不同、适用场景略有差异。
定时器版:延迟执行,保证最小间隔
原理是用 setTimeout 缓存一次执行请求,若在延时期间再次触发,则清除旧定时器、重设新定时器。最终函数只在“最后一次触发后的 delay 毫秒”执行一次(尾部执行)。
适合需要稳定节奏、且不强求立即响应的场景,比如调整窗口大小后重新计算布局。
- 首次触发不会立即执行,需等待 delay 时间后才执行
- 连续触发期间,只有最后一次有效,前面的都被覆盖
- 代码简洁,逻辑直观,不易出错
时间戳版:立即执行 + 节制后续,保证首尾响应
原理是记录上一次执行的时间戳(previous),每次触发时对比当前时间与 previous 的差值。若超过 delay,就立即执行并更新 previous;否则忽略本次调用。
立即学习“Java免费学习笔记(深入)”;
适合对响应及时性有要求的场景,比如滚动监听中希望首次滚动立刻处理,之后再限频。
- 第一次触发立即执行
- 后续触发是否执行,取决于距上次执行是否已过 delay
- 不依赖定时器,无清除/重设开销,性能略优
关键区别总结
两者不是“谁更好”,而是“谁更合适”:
- 执行时机:时间戳版首调即执行,定时器版首调要等 delay 后才执行
- 执行次数:时间戳版在单位时间内最多执行 ⌊t/delay⌋ 次;定时器版在持续触发下,实际执行间隔可能略大于 delay(因重置导致)
- 内存与副作用:定时器版需管理 timer ID,存在 clearTimeout 开销;时间戳版仅维护一个数字变量,更轻量
- 可预测性:时间戳版行为更确定;定时器版在快速连续触发下,可能“漏掉”本该在中间执行的一次(因不断重置)
简单可运行示例对比
假设 delay = 500ms,用户在 0ms、100ms、200ms、600ms、700ms 触发:
- 时间戳版:0ms 执行 → 600ms 执行(因 600−0≥500)→ 700ms 不执行(700−600
- 定时器版:0ms 设定时器 → 100ms 清除重设 → 200ms 再清再设 → 600ms 设定时器 → 700ms 清除重设 → 最终在 1100ms 执行(600+500)→ 共 1 次,且延迟明显


















