1. 卡顿的本质:从帧率到垂直同步

做前端性能优化这么多年,我始终觉得——理解卡顿,比学会优化技巧更重要。你连敌人长什么样都不知道,怎么打?

今天咱们就从最底层开始,把「卡顿」这层窗户纸捅破。

1.1 帧率(FPS)—— 流畅度的硬指标

FPS,全称 Frames Per Second,每秒传输帧数。说白了就是——你的屏幕每秒钟能刷新多少张画面。

我习惯把帧率想象成翻页动画书:

  • 10 FPS:像幻灯片,一卡一卡的
  • 30 FPS:勉强能看,但明显不流畅
  • 60 FPS:丝滑,人眼基本感觉不到卡顿
  • 120 FPS:极致流畅,但普通显示器看不出区别

60 FPS 为什么是黄金标准?

因为人眼的视觉暂留效应大约在 16.67ms。60 FPS 意味着每帧耗时 16.67ms,刚好卡在这个阈值上。再慢,人眼就能感知到「跳帧」了。

我在项目中遇到过不少同学,一上来就盯着 FPS 数字看。其实 FPS 只是结果,不是原因。真正要搞懂的,是 为什么 FPS 会掉。

1.2 掉帧的底层原理 —— 渲染流水线

一个页面从代码到屏幕,要经过这么几步:

  1. JavaScript 执行 —— 处理事件、执行动画逻辑
  2. 样式计算 —— 计算 CSS 规则匹配
  3. 布局 —— 计算元素位置和尺寸
  4. 绘制 —— 生成绘制指令
  5. 合成 —— 将图层合并成最终画面
  6. 提交到 GPU —— 显示到屏幕

这六步必须在 16.67ms 内完成。任何一步超时,都会导致这一帧「掉队」。

注意: 掉帧 ≠ 卡顿。偶尔掉一帧人眼察觉不到,连续掉帧才会产生卡顿感。我见过很多优化方案,把精力花在「消灭所有掉帧」上,其实没必要。重点应该是 减少连续掉帧。

1.3 垂直同步(VSync)—— 屏幕的节拍器

你想想看,如果没有 VSync,会发生什么?

GPU 渲染完一帧就立刻推送到屏幕。但屏幕刷新是有固定周期的(比如 60Hz 显示器每 16.67ms 刷新一次)。如果 GPU 在屏幕刷新到一半时推送新画面,就会出现 画面撕裂——上半部分是旧帧,下半部分是新帧。

VSync 的作用就是:强制 GPU 等待屏幕刷新完成后再推送下一帧。

模式 工作原理 优点 缺点
关闭 VSync GPU 渲染完立即推送 帧率不受限,操作延迟低 画面撕裂
开启 VSync GPU 等待屏幕刷新完成 画面完整,无撕裂 帧率被锁定在屏幕刷新率,可能引入输入延迟
自适应 VSync 帧率高于刷新率时开启,低于时关闭 兼顾流畅和完整 实现复杂,部分场景仍有撕裂

嗯,这里要注意——VSync 不是万能的。我曾经在一个项目中,发现页面偶尔卡顿,排查了半天,最后发现是 VSync 导致的帧率抖动。因为 GPU 渲染时间刚好卡在 16.67ms 边缘,VSync 让它等了一帧,反而造成了掉帧。

1.4 从帧率到卡顿的完整链路

为了让你更直观地理解,我画了一张图:

卡顿产生的完整链路 JS 执行 样式计算 布局 绘制 合成 GPU 提交 VSync 等待 屏幕显示 某一步超时 > 16.67ms 这一帧被跳过(掉帧) 连续掉帧 → 卡顿 关键点: • 每一帧必须在 16.67ms 内完成全部 6 步 • VSync 保证画面完整,但可能引入额外延迟

1.5 实战中如何定位卡顿

光懂理论不行,得能落地。我分享几个我在项目中常用的方法:

我的排查三板斧:

  1. Chrome DevTools Performance 面板 —— 录制一段操作,看每一帧的耗时分布。红色标记就是掉帧。
  2. Frame Rendering Stats —— 在 Chrome 里打开 chrome://gpu,查看 GPU 渲染状态。
  3. 手动打点 —— 用 performance.now() 在关键步骤前后打点,计算耗时。

举个例子,我曾经接手过一个 H5 活动页,滑动时卡得不行。打开 Performance 面板一看,好家伙——布局(Layout)耗时 40ms,远超 16.67ms 的预算。

原因是什么?页面里用了大量 position: absolute 的动画,每次滚动都触发了全量重排。后来改成 transform 实现,布局耗时直接降到 2ms。

避坑指南: 我曾经以为 FPS 越高越好,于是在一个项目中强行把帧率推到 120 FPS。结果呢?手机发烫、电池狂掉,用户反而投诉了。后来我才明白——稳定 60 FPS 比偶尔 120 FPS 更重要。性能优化的目标不是跑分,是用户体验。

1.6 小结

这一章我们搞清楚了:

  • 卡顿的本质 —— 渲染流水线中某一步超时,导致帧被跳过
  • 60 FPS 的黄金标准 —— 每帧 16.67ms 的硬约束
  • VSync 的作用 —— 协调 GPU 和屏幕的节奏,避免撕裂
  • 掉帧 ≠ 卡顿 —— 连续掉帧才是真凶

嗯,基础打牢了,后面咱们才能聊具体的优化手段。记住一句话:先理解,再优化。