FPS曲线是定位滑动卡顿源头的第一步,需结合Main轨道、Summary面板、Call Tree和Memory面板,分别识别强制布局、高频小任务、长脚本执行及内存抖动等具体原因。

看 FPS 曲线本身不能直接告诉你“为什么卡”,但它是定位滑动卡顿源头的第一把钥匙——关键在于把帧率波动和下方时间轴里的渲染行为对齐,找到那一帧里真正吃掉主线程的元凶。
盯住 FPS 轨道上的“凹坑”和“抖动”
FPS 图表中绿色柱子代表每秒渲染帧数。60fps 是理想状态,对应每帧 16.7ms 预算。滑动时出现以下情况要立即关注:
- 连续几帧掉到 30fps 以下:大概率存在长任务或强制同步布局(Forced Layout)
- 单帧突然跌到 10–20fps(即单帧耗时 >50ms):点开 Main 轨道,找那块标红/深黄的长条,它就是当帧的瓶颈
- 帧率忽高忽低、锯齿状抖动(比如 60→45→58→32):不是单个大任务,而是高频小任务挤压,比如未节流的 scroll 事件、每帧都 new 数组、或频繁触发 getBoundingClientRect()
联动 Main 轨道,定位具体操作类型
鼠标悬停在 FPS 凹坑对应的帧上,看下方 Summary 面板:
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
- 显示 “Layout” 或 “Forced Layout”:说明 JS 在读取 offsetTop、clientWidth 等布局属性后立刻修改样式,触发了同步回流
- 显示 “Paint” 占比异常高:可能是 CSS 动画没加 will-change、背景图未压缩、或元素有透明度渐变但未启用硬件加速
- 显示 “Scripting” 块又宽又密(尤其在滚动中持续出现):检查是否在 scroll 事件里做了 DOM 查询、计算或 setState,且没做节流
- “Idle” 时间极少甚至为零:主线程被占满,连空闲时间都没有,典型特征是第三方 SDK 或分析脚本在后台密集上报
展开 Call Tree,锁定真实耗时函数
点击 Main 轨道中那个可疑的色块(哪怕只有 25ms),切换到底部 Call Tree 标签,按 “Self Time” 降序排列:
- 如果 top 函数是某个 getter(如 el.offsetHeight)、或 layout 相关 API:确认是否在循环中反复调用,或与 style 修改混写
- 如果 top 是 Array.from、JSON.parse、或大量 for 循环:说明滚动中做了不该做的计算,应移到 rAF 后或用 requestIdleCallback 延后
- 如果 top 是 React 的 render 或 Vue 的 patch:说明虚拟 DOM diff 过重,考虑用 memo、shouldComponentUpdate 或虚拟滚动优化列表
结合 Memory 面板查内存抖动
滑动卡顿有时不来自 CPU,而来自 GC。打开 Memory 面板,勾选 “Allocation instrumentation on timeline”,然后滚动页面:
- 看到密集的小蓝条(代表对象分配):说明每帧都在创建新数组、闭包或临时对象
- 紧接着出现灰色竖线(minor GC):GC 打断了帧节奏,哪怕只停 3–5ms,也足以让一帧超预算
- 常见场景:scroll 事件里每次生成新 Promise、监听器内反复构造 Date 对象、或用字符串拼接代替 documentFragment 批量插入

















