滚动事件需节流以避免高频触发导致卡顿、CPU飙升或重排重绘过多;通过设定最小执行间隔(如100ms)控制函数执行频率,兼顾响应性与性能。

函数节流(Throttle)在滚动事件中,核心是控制函数执行频率,避免因高频触发导致性能问题,比如页面卡顿、CPU占用飙升或重排重绘过多。
为什么滚动事件需要节流
用户快速滚动时,scroll 事件可能每秒触发几十甚至上百次。若每次触发都执行 DOM 操作、计算位置或发起请求,浏览器来不及处理就会丢帧,造成卡顿。节流通过设定最小执行间隔(如 100ms),确保函数不会过于频繁地运行,兼顾响应性与性能。
节流函数的简易实现
一个轻量、可复用的节流函数:
function throttle(fn, delay) {
let lastTime = 0;
return function(...args) {
const now = Date.now();
if (now - lastTime >= delay) {
fn.apply(this, args);
lastTime = now;
}
};
}
使用方式:
立即学习“Java免费学习笔记(深入)”;
const handleScroll = throttle(() => {
console.log('滚动位置:', window.pageYOffset);
}, 100);
<p>window.addEventListener('scroll', handleScroll);
注意 this 和参数的正确传递
原生事件监听中,this 指向 window,但节流函数内部需保持上下文一致。上面实现中用 fn.apply(this, args) 确保了这一点。如果传参涉及事件对象,建议在闭包中捕获或显式传入:
- 直接使用
event可能为空(被动监听下 event 不可被 preventDefault) - 如需精确坐标,推荐用
window.scrollX/window.scrollY替代依赖 event - 避免在节流函数内频繁读取
offsetTop、getBoundingClientRect()等触发重排的属性
和防抖(Debounce)的区别与选型
节流保证“固定间隔至少执行一次”,适合实时反馈类场景(如滚动中更新导航高亮、懒加载临界判断);防抖则只在停止触发后执行,适合搜索输入、窗口缩放等终态操作。
滚动场景中:
- 要做“滚动中持续监听是否进入某区域” → 选节流
- 只关心“滚动结束后的最终位置”(如保存滚动锚点)→ 可考虑防抖
- 现代方案也可结合
IntersectionObserver替代部分节流逻辑,更高效且无需手动管理时机


















