节流函数核心是在固定时间间隔内最多执行一次事件处理函数,常用定时器+状态标记实现,支持尾部执行、取消及头部执行等增强功能。

节流函数(Throttle)的核心思路是:在指定时间间隔内,只允许事件处理函数最多执行一次,其余调用被忽略或延迟到下个周期。用定时器实现时,常用“定时器+状态标记”配合,确保高频触发下稳定限频。
基本实现原理:定时器 + 闭包状态
关键在于维护一个 timer 变量和一个“是否正在等待执行”的状态。每次触发时,如果定时器未启动,就设置定时器;如果已存在定时器,则跳过本次执行,等定时器清空后才允许下一次尝试。
- 不使用防抖的“重置计时”逻辑,而是固定周期内只执行一次
- 通常采用“尾部执行”策略:即在每个周期结束时执行最后一次有效调用(也可选头部执行,即周期开始时立即执行一次)
- 闭包保存 timer 和上一次参数,保证上下文不丢失
常见写法:尾部节流(推荐)
这是最常用的节流方式,适合滚动、鼠标移动等场景,避免频繁计算但又不丢失最终状态:
function throttle(func, delay) {
let timer = null;
return function (...args) {
if (!timer) {
timer = setTimeout(() => {
func.apply(this, args);
timer = null;
}, delay);
}
};
}
使用示例:
window.addEventListener('scroll', throttle(() => {
console.log('滚动节流执行');
}, 100));
说明:连续滚动时,每 100ms 最多执行一次,且执行的是该周期内最后一次触发时的调用。
支持取消与立即执行的增强版
实际项目中常需手动清理定时器(如组件卸载时),或希望首次触发立刻执行(头部节流):
- 添加 cancel 方法清除待执行任务
- 通过 leading 参数控制是否首次立即执行
- 通过 trailing 控制是否在周期末尾补一次执行
简化版带 cancel 支持:
function throttle(func, delay) {
let timer = null;
const throttled = function (...args) {
if (!timer) {
timer = setTimeout(() => {
func.apply(this, args);
timer = null;
}, delay);
}
};
throttled.cancel = () => {
if (timer) {
clearTimeout(timer);
timer = null;
}
};
return throttled;
}
注意事项与常见误区
节流不是万能的,需结合场景判断是否适用:
- this 和参数丢失:记得用 apply 或箭头函数绑定上下文,否则 func 内部 this 指向可能错误
- delay 过小失效:设为 0 或太小(如 1ms)几乎不起作用,建议至少 16ms(接近一帧)或根据业务容忍度设为 50–200ms
- 与防抖混淆:节流强调“固定频率执行”,防抖强调“停止后延迟执行”,二者目的不同,不可互换
- 不适用于需要即时响应的交互:比如拖拽实时位置更新,节流可能导致卡顿,此时更适合 requestAnimationFrame
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











