节流通过每16ms最多执行一次滚动处理,匹配60FPS刷新节奏,结合requestAnimationFrame实现精准调度,并配合硬件加速(transform/will-change)与剥离重操作,确保滚动流畅。
高频滚动时,浏览器每秒可能触发上百次
事件,若每次都执行 DOM 计算、样式更新或状态同步,主线程很快超载,帧率跌破 60FPS,用户立刻感知卡顿。函数节流不是“减少响应”,而是把密集事件“对齐到渲染节奏”,让逻辑只在合适时机运行。
为什么节流能守住 60FPS
浏览器理想刷新周期是 16.7ms(1000 ÷ 60)。节流将滚动处理限制在每 16ms 最多执行一次,正好匹配 requestAnimationFrame 的调度节奏。它不丢事件,也不等停止——而是“匀速采样”,确保视觉反馈连续、计算负载可控。
用 requestAnimationFrame 实现精准节流
比
或时间戳轮询更可靠,因为它与屏幕刷新强绑定,不会因 JS 阻塞而错失帧。
记录上一次执行时间,仅当间隔 ≥ 16ms 才触发下一帧处理
把实际逻辑包裹在
内,交由浏览器统一调度
避免在节流回调里做 layout 强制读取(如
),否则会触发同步重排
示例代码:
稿定在线PS
PS软件网页版
下载
节流 + 硬件加速 = 渲染零压力
节流解决“执行太密”,硬件加速解决“绘制太重”。两者必须配合:
滚动中需动画的元素(如吸顶栏、视差层)用
替代
或
给该元素加
,提前提示浏览器启用 GPU 图层
避免在节流回调里修改
、
、
等触发布局的属性
哪些操作必须移出节流回调
节流只保“响应节奏”,不保“执行轻量”。以下操作即使节流了也会拖垮帧率,应彻底剥离:
图片解码或大尺寸 Canvas 绘制(改用
+
)
长列表的全量 DOM 更新(改用虚拟滚动,只渲染可视区 5–10 个 item)
复杂状态计算(如实时 filter 数组、格式化大量日期——移到 Web Worker 或防抖后执行)
scrollsetTimeoutrequestAnimationFrameoffsetHeightlet lastTime = 0;
window.addEventListener('scroll', () => {
const now = Date.now();
if (now - lastTime >= 16) {
requestAnimationFrame(() => {
// 这里放位置判断、class 切换、懒加载触发等轻量逻辑
updateStickyHeader();
lastTime = now;
});
}
});transform: translateY()topmargin-topwill-change: transformwidthheightleftImage.decode()loading="lazy"