节流通过定时器开关控制回调执行频次,确保指定间隔内最多执行一次;常见实现用settimeout加标记位,视觉场景推荐requestanimationframe以匹配刷新率。

鼠标移动事件(mousemove)触发频率极高,频繁执行回调会显著拖慢页面性能。节流(throttle)是控制执行频次的有效手段——它确保回调函数在指定时间间隔内最多执行一次,而非每次触发都响应。
节流的核心逻辑:定时器开关控制
节流不是简单地“延迟执行”,而是通过一个开关(如布尔标记或定时器 ID)阻止重复进入执行流程。常见实现方式是:首次触发时立即执行,并启动一个定时器;在定时器未结束前的后续触发全部忽略;定时器结束后重置开关,允许下一次执行。
- 用
setTimeout+ 标记位是最易理解的写法 - 避免使用
setInterval,它无法精准匹配事件触发节奏 - 注意清除旧定时器,防止多次触发累积多个定时器
手写一个轻量节流函数
以下是一个兼容性好、无依赖的节流封装:
function throttle(fn, delay) {
let timer = null;
return function(...args) {
if (!timer) {
fn.apply(this, args);
timer = setTimeout(() => {
timer = null;
}, delay);
}
};
}
使用示例:
const handleMove = throttle((e) => {
console.log('鼠标位置:', e.clientX, e.clientY);
}, 60); // 约每秒最多16次(1000ms / 60ms ≈ 16.7)
document.addEventListener('mousemove', handleMove);
用 requestAnimationFrame 实现更流畅的节流
如果目标是视觉相关操作(比如跟随鼠标更新元素位置),requestAnimationFrame 是比定时器更优的选择——它天然与屏幕刷新率同步(通常 60fps),且在页面不可见时自动暂停。
- 它不严格限制“每秒多少次”,而是“每一帧最多执行一次”
- 适合需要平滑动画或 DOM 更新的场景
- 需配合标记变量防止重复调度
let isRafPending = false;
function rafThrottle(fn) {
return function(...args) {
if (!isRafPending) {
isRafPending = true;
requestAnimationFrame(() => {
fn.apply(this, args);
isRafPending = false;
});
}
};
}
document.addEventListener('mousemove', rafThrottle((e) => {
element.style.left = e.clientX + 'px';
element.style.top = e.clientY + 'px';
}));
实际应用中的关键细节
节流不是万能药,需结合场景选型和微调:
- 不要过度节流:设成 200ms 可能导致交互卡顿,一般 40–100ms 较平衡
-
解除监听时记得清理:若使用
setTimeout节流,需保存返回的 timer ID 并手动clearTimeout -
注意 this 和参数传递:箭头函数会丢失上下文,推荐用
fn.apply(this, args)或显式绑定 - 现代项目可直接用 Lodash 的
_.throttle,支持取消、边缘触发等高级选项
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











