节流的核心是通过闭包保存上次执行时间戳以控制函数执行频率,使用 date.now() 获取高精度时间,返回的封装函数根据时间差决定是否执行原函数并更新时间戳。

节流的核心是控制函数执行频率,闭包用来保存上一次执行的时间戳,从而判断是否满足再次执行的条件。
用闭包保存上次执行时间
闭包让内部函数能持续访问外部函数定义的变量(比如 lastTime),避免每次调用都重置状态。时间戳通常用 Date.now() 或 performance.now() 获取,精度更高且不受系统时间修改影响。
- 外部函数接收目标函数和间隔时间(如 100ms),返回一个封装后的新函数
- 新函数内部读取并更新闭包中的 lastTime,决定是否执行原函数
- 不依赖全局变量,每个节流实例独立维护自己的时间状态
基础节流实现(时间戳 + 闭包)
以下是一个典型实现:
function throttle(func, delay) {
let lastTime = 0;
return function(...args) {
const now = Date.now();
if (now - lastTime >= delay) {
func.apply(this, args);
lastTime = now;
}
};
}这里 lastTime 被闭包捕获,每次调用返回的函数都能读写它。注意:该版本是“立即执行”型(首次触发立刻运行),适合监听鼠标移动、滚动等高频事件。
支持配置首次/末次执行时机
实际项目中常需灵活控制——比如希望延迟执行(即等待 delay 后再执行最后一次),这时可在闭包中额外保存定时器引用,并结合 setTimeout 实现。但无论哪种模式,闭包始终承担着记录关键状态(时间戳或定时器 ID)的角色。
- “首次执行”:判断当前时间与上次执行时间差 ≥ delay,就立即执行并更新时间戳
- “末次执行”:每次触发都重设定时器,delay 后执行,依赖闭包保存 timer 引用
- 两者可组合为“双执行”模式(首尾各一次),仍靠闭包维持两个时间点或标志位
注意事项:this 和参数传递
闭包本身不改变 this 绑定,所以要用 func.apply(this, args) 正确传递上下文和参数。箭头函数不可替代普通函数,否则无法动态获取调用时的 this 和 arguments。
- 避免直接写
func(...args)—— 会丢失原始 this - 不要在闭包外声明 lastTime,否则多个节流函数共用同一时间戳,互相干扰
- 如需重置状态(比如重新开始计时),可暴露一个 reset 方法,同样通过闭包访问内部变量
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











