节流函数采用时间戳+定时器双机制:时间戳控制最小执行间隔,确保首次立即执行且后续按周期触发;定时器兜底保障最后一次高频触发不丢失,通过清空重设避免重复执行。

节流函数用时间戳 + 定时器双保险,核心是:**既靠时间戳控制最小间隔,又靠定时器兜底确保最后一次触发不丢失**。单用时间戳会丢尾调用,单用定时器可能频繁重置导致延迟不可控,两者结合才能兼顾“频率限制”和“执行保底”。
时间戳部分:记录上一次执行时间
每次调用节流函数时,先对比当前时间与上次执行时间的差值。若未达到设定间隔(如 300ms),直接返回,不执行目标函数。
- 用 Date.now() 获取毫秒级时间戳,比
new Date().getTime()更简洁高效 - 初始
previous = 0,首次调用必执行(因为Date.now() - 0 > delay) - 执行后立即更新
previous = Date.now()
定时器部分:兜底触发最后一次“被拦截”的调用
仅靠时间戳会在连续高频触发末尾漏掉一次——比如用户拖拽结束那一下。这时需用定时器在“本次调用后 delay 时间”再检查:若期间没再触发,就补执行;若又触发了,就清空重设。
- 每次调用时先 clearTimeout(timer),避免旧定时器干扰
- 然后 setTimeout 设置新定时器,内部判断:若当前时间距上次执行 ≥ delay,才执行(防重复)
- 执行后仍要更新
previous,保持时间戳逻辑一致
完整实现示例(可直接用)
// throttle(fn, delay) 返回节流后的函数
立即学习“Java免费学习笔记(深入)”;
function throttle(fn, delay) {
let previous = 0;
let timer = null;
<p>return function(...args) {
const now = Date.now();</p><pre class="brush:php;toolbar:false;">// 时间戳控制:未到间隔,跳过
if (now - previous < delay) {
clearTimeout(timer);
timer = setTimeout(() => {
if (Date.now() - previous >= delay) {
fn.apply(this, args);
previous = Date.now();
}
}, delay);
return;
}
// 到间隔了,直接执行
fn.apply(this, args);
previous = now;}; }
关键细节提醒
- timer 要声明在闭包内,否则多个节流实例会互相覆盖
-
apply(this, args) 保证 this 和参数正确传递,别写成
fn(...args)(会丢失 this) - 实际使用中建议加防抖式“立即执行首调”开关,但本方案默认按标准节流行为:首调立即执行,后续按间隔来
- 测试时可用
console.log(Date.now())验证时间戳是否稳定推进,定时器是否只在必要时触发


















