节流函数核心是固定频率执行,分时间戳版(立即执行、响应及时但可能漏执行)和定时器版(延迟执行、需加mustrundelay防永久不执行),需注意参数透传、闭包隔离、时间精度及典型误用。

节流函数的核心是“固定频率执行”,不是等事件停了再执行,而是保证在单位时间内最多只跑一次。它适合 scroll、resize、mousemove 这类需要持续反馈但又不能太频繁的场景。
时间戳版:立即执行,更常用
每次触发时用当前时间戳和上一次执行时间比较,差值够了就执行并更新时间戳。
- 优点:响应及时,第一次触发立刻执行
- 缺点:如果用户持续高频触发(比如快速滚动),可能在间隔边界处漏掉一次执行
- 关键点:lastTime 初始化为 0,首次调用必然满足条件
定时器版:延迟执行,更稳定
用 setTimeout 控制执行时机,每次触发都清除旧定时器、设置新定时器;但加一层判断,避免完全不执行。
- 问题:纯定时器版在持续触发下可能永远不执行(比如每 50ms 触发一次,delay 设为 100ms)
- 优化思路:引入 mustRunDelay(也叫“强制执行间隔”),确保哪怕一直触发,每隔一段时间也必须执行一次
- 实现逻辑:记录首次触发时间 t_start,若当前时间 - t_start ≥ mustRunDelay,直接执行;否则走定时器延迟执行
参数与上下文处理细节
实际使用中容易忽略几个关键点:
-
arguments 透传:要用
fn.apply(this, args)而不是fn(...args),兼容老环境且保留 this 绑定 - 闭包变量隔离:每个 throttle 实例应有独立的 lastTime / timer / t_start,避免多个节流函数互相干扰
-
延迟时间单位统一:推荐用
Date.now()或performance.now(),比new Date().getTime()更精准
典型误用与规避建议
常见坑点包括:
- 把 throttle 当 debounce 用——比如输入框搜索,用节流会导致中间关键词没发请求
- 没清空定时器导致内存泄漏或重复执行(尤其在组件卸载时)
- 忽略 this 指向,绑定在 DOM 事件上时直接传箭头函数会丢失上下文
- delay 值设得太小(如 16ms)反而加重负担,一般 scroll 推荐 100–160ms,resize 可放宽到 250ms
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











