运行时性能是您的页面在运行时的表现,而不是加载。 就 RAIL 模型而言,本文介绍的方法对于分析页面的响应、动画和空闲阶段非常有用。
在隐身模式下打开谷歌浏览器。 隐身模式可确保 Chrome 以干净的状态运行。 例如,如果您安装了很多扩展,这些扩展可能会在您的性能测量中产生干扰。
在您的隐身窗口中加载以下页面。 这是您要分析的演示。 该页面显示了一堆上下移动的蓝色小方块。
https://googlechrome.github.io/devtools-samples/jank/
Simulate a mobile CPU
移动设备的 CPU 能力远低于台式机和笔记本电脑。 每当您分析页面时,请使用 CPU 节流来模拟您的页面在移动设备上的表现。
下列选项,CPU 4x slowdown, 模拟出运算速度只有当前 1/4 的 CPU:
Set up the demo
很难为所有读者创建一个始终如一的运行时性能演示。 因此 Google 准备了一个允许自定义屏幕上出现元素数量的 web 应用,以确保您的体验与您在本教程中看到的屏幕截图和描述相对一致,而不管您的计算机的硬件配置如何。
(1) 继续单击 Add 10,直到蓝色方块的移动速度明显比以前慢。 在高端机器上,可能需要大约 20 次点击。
(2) 单击优化。 蓝色方块应该移动得更快更平稳。
如果您没有看到优化和未优化版本之间的明显差异,请尝试多次单击“减去 10”并重试。 如果添加太多蓝色方块,只会使 CPU 使用率最大化,并且不会看到两个版本的结果有很大差异。
Record runtime performance
当您运行页面的优化版本时,蓝色方块移动得更快。 这是为什么? 两个版本都应该在相同的时间内将每个方格移动相同的空间。 在性能面板中进行录制,了解如何检测未优化版本中的性能瓶颈。
点击 Performance 面板的 Record 图标,开始录制:
等几秒钟后,点击 Stop:
下面介绍如何解读 Performances 面板生成的统计数据。
Analyze frames per second
衡量任何动画性能的主要指标是每秒帧数 (FPS)。当动画以 60 FPS 运行时,意味着较好的用户体验。
查看 FPS 图表。 每当您看到 FPS 上方的红色条时,就意味着帧率下降得太低,可能会损害用户体验。 一般来说,绿色条越高,FPS 越高。
如下图所示,我开启了 recording,然后重复点击 Add 10,在此过程中,能看到代表 FPS 低于 60 的红线逐渐升高,然后在 CPU 栏,代表 Rendering 的紫色图例越来越多。
将鼠标悬停在 FPS、CPU 或 NET 图表上。 DevTools 显示了当时页面的屏幕截图。 左右移动鼠标可重播录音。 这称为擦洗(scrubbing),它对于手动分析动画的进程很有用。
看这个 frames 栏:
在框架部分,将鼠标悬停在其中一个绿色方块上。 DevTools 会向您显示该特定帧的 FPS。 每帧可能远低于 60 FPS 的目标。
Bonus: Open the FPS meter
我们还可以使用 FPS meter 观测一个网页实时的 FPS 数据。
快捷键:Control+Shift+P 选择 show rendering:
在渲染选项卡中,启用 FPS Meter。即下图这个 checkbox:
视口的右上角会出现一个新的叠加层。能显示实时的 FPS 数据:
我们在 summary 标签页里看到,该 web 应用的瓶颈在 rendering:
展开 main 部分。 DevTools 会向您显示主线程上随时间变化的活动火焰图。 x 轴表示随时间的记录。 每个条形代表一个事件。
更宽的条形意味着该事件花费的时间更长。 y 轴代表调用堆栈。 当您看到事件堆叠在一起时,这意味着较高的事件导致较低的事件。
recording 中有很多数据。 通过单击、按住并将鼠标拖动到“概览”(包括 FPS、CPU 和 NET 图表的部分)上,放大单个动画帧触发事件。 主要部分和摘要选项卡仅显示所选 recording 部分的信息。
请注意 Animation Frame Fired 事件右上角的红色三角形。 每当您看到红色三角形时,即表示可能存在与此事件相关的问题的警告。
每当执行 requestAnimationFrame() 回调时,就会发生 Animation Frame Fired 事件。
单击动画帧触发事件。 “摘要”选项卡现在显示有关该事件的信息。 注意揭示链接。 单击它会导致 DevTools 突出显示启动 Animation Frame Fired 事件的事件。 另请注意 app.js:94 链接。 单击它会将您跳转到源代码中的相关行。
app.update = function (timestamp) {
for (var i = 0; i < app.count; i++) {
var m = movers[i];
if (!app.optimize) {
var pos = m.classList.contains('down') ?
m.offsetTop + distance : m.offsetTop - distance;
if (pos < 0) pos = 0;
if (pos > maxHeight) pos = maxHeight;
m.style.top = pos + 'px';
if (m.offsetTop === 0) {
m.classList.remove('up');
m.classList.add('down');
}
if (m.offsetTop === maxHeight) {
m.classList.remove('down');
m.classList.add('up');
}
} else {
var pos = parseInt(m.style.top.slice(0, m.style.top.indexOf('px')));
m.classList.contains('down') ? pos += distance : pos -= distance;
if (pos < 0) pos = 0;
if (pos > maxHeight) pos = maxHeight;
m.style.top = pos + 'px';
if (pos === 0) {
m.classList.remove('up');
m.classList.add('down');
}
if (pos === maxHeight) {
m.classList.remove('down');
m.classList.add('up');
}
}
}
frame = window.requestAnimationFrame(app.update);
}
使用键盘上下箭头切换事件的显示:
在 app.update 事件下,有一堆紫色事件。 如果它们更宽,看起来好像每个上面都有一个红色三角形。 现在单击紫色布局事件之一。 DevTools 在摘要选项卡中提供了有关事件的更多信息。 事实上,有一个关于强制回流的警告(布局的另一种说法)。
先选中 app.update, 然后按键盘下箭头,再左右移动,找到这些 forced reflow 的代码,同样可以点击超链接看到引起回流的准确代码行数:
比如第 71 行的 m.offsetTop 引起回流:
这段代码的问题在于,在每个动画帧中,它会更改每个方块的样式,然后查询每个方块在页面上的位置。 因为样式改变了,浏览器不知道每个方块的位置是否改变,所以它必须重新布局方块以计算它的位置。 请参阅避免强制同步布局以了解更多信息。
更多Jerry的原创文章,尽在:"汪子熙":
网友评论