闭包通过捕获并维护lastTime时间戳实现节流,结合performance.now()精确判断时间间隔,确保函数在阈值内最多执行一次。

闭包本身不直接实现“节流”,但它能稳定保存计时状态,为节流逻辑提供可靠的时间基准。关键在于用闭包捕获并维护上一次执行的时间戳,再结合时间差判断是否放行当前调用。
节流的核心逻辑依赖闭包保存时间状态
节流要求函数在指定时间间隔内最多执行一次。要判断“距上次执行是否已过阈值”,就必须记住上次执行的时刻——这个时间戳不能放在全局变量里(易被污染),也不能每次重新计算(失去意义)。闭包天然适合:外层函数定义时间变量,内层函数持续访问并更新它。
- 每次调用节流后的函数时,先读取闭包中保存的
lastTime - 用
performance.now()获取当前高精度时间 - 若当前时间减
lastTime≥ 间隔阈值,则执行原函数,并更新lastTime - 否则跳过,不执行也不更新
用 performance.now() 实现毫秒级精确计时
performance.now()返回以毫秒为单位、精度达微秒级的浮点数,不受系统时间调整影响,比Date.now()或setTimeout计时更可靠,特别适合节流这类对时间敏感的场景。
- 避免使用
new Date().getTime():受系统时钟回拨影响,可能导致节流失效 - 不依赖
setTimeout延时模拟:那是防抖思路,节流强调“固定窗口内只允一次” - 闭包确保每次调用都对比的是同一套时间上下文,不会因作用域丢失而重置
一个可复用的节流函数封装
下面是一个带闭包、使用performance.now()的节流实现:
(注意:此版本不自动触发延迟执行,是“立即执行+冷却期”模式)
- 外层函数接收原函数
fn和间隔delay,返回节流后的新函数 - 闭包内声明
lastTime = 0,初始值设为 0 更安全(首次必执行) - 返回的函数使用
...args接收任意参数,保持调用方式不变 - 执行前检查时间差,满足条件才运行
fn.apply(this, args)
示例代码:
function throttle(fn, delay) {<br> let lastTime = 0;<br> return function(...args) {<br> const now = performance.now();<br> if (now - lastTime >= delay) {<br> fn.apply(this, args);<br> lastTime = now;<br> }<br> };<br>}
调用:const throttledResize = throttle(handleResize, 16); // 约60fps
和防抖、普通定时器的本质区别
节流不是“等停了再执行”,也不是“每delay毫秒强制执行一次”。它是在高频触发中主动丢弃多余调用,同时保证最低频率响应。闭包让这个判断过程干净独立:
- 防抖(debounce):闭包记的是
timerId,每次触发都清旧启新,最终只执行最后一次 - 普通
setInterval:无法响应事件流节奏,容易错过关键帧或重复执行 - 节流闭包:只关心“我上次什么时候干的”,不干预事件源,也不承诺执行时机,只守门


















