编写高效代码¶
在调试页面时,工具会因为添加的检测而减慢网站速度。在开发 DevTools 时,我们应该努力减少其影响。首先,因为使用延迟的 UI 非常痛苦,而且有些工具会记录时间。例如,网络监控器会记录 HTTP 请求时间。如果工具显著减慢了 Firefox 的速度,则会使这些测量结果错误。
为了在处理性能问题时保持高效,你应该始终关注一个特定的用户场景。它可能是
用户报告的某个特定交互速度缓慢的 Bug 报告,
或者你可以通过查看最常见的用法来尝试提高工具的整体性能。这里需要注意的是,需要有一些可重现的步骤,以便你可以手动重复这些步骤以记录配置文件。此外,如果可以通过测试脚本重放,则效果会更好。你可以将测试脚本保存为新的性能测试。
不要猜测 — 使用 Profiler¶
第一步是重现场景时记录一个配置文件。
以下是 Firefox 文档中关于 如何安装 Profiler 并记录配置文件 以及 如何解读配置文件 的说明。
在查看配置文件时,有一些关于 DevTools 架构的特殊情况需要注意。
调整 Profiler 默认设置¶
默认缓冲区大小 (9MB) 太小。如果你不增加它,你可能会很容易错过数据,并且只能看到最后几秒的记录。要增加缓冲区大小,请点击 Firefox 工具栏中的 Profiler 加载项图标,并将其设置为 360MB,如下所示:
另一个值得一提的用于 DevTools 调试的设置是 Interval
。Profiler 只会基于此 Interval
记录样本。如果你想查看更细粒度的堆栈跟踪,可以将此间隔减少到 0.1ms,但只有在你确实需要时才这样做,因为它会在记录时使 Firefox 的速度变得更慢,并且测量的时长也会更长。
DevTools UI 运行在父进程中¶
当你调试工具前端(例如面板)时,请务必选择 Main Thread
行。它应该具有浅蓝色的背景,如下所示:
否则,绝大多数 DevTools 后端(DevToolsServer、actor 等)都位于内容进程中。因此,如果你正在调试它们,则应选择其中一个 Content
行。
大部分 DevTools 代码库都是用 Javascript 编写的¶
在调用树中,可以通过此菜单列表使用 JS
进行更轻松的过滤:
但请注意,你可能需要切换回 Combined
才能了解为什么某些特定的 Javascript 方法运行缓慢。
DevTools 的有用过滤字符串:¶
require
有助于突出显示模块加载的成本DevTools 使用两种 URL
chrome://devtools/
用于所有面板文档。使用此过滤器查看所有面板文档的成本:resource://devtools/
用于所有 Javascript 模块。使用此过滤器查看所有模块的成本:
手动记录时长¶
有时,将重点放在非常具体的代码片段上并手动记录其时间非常有用。例如,当你识别出一个运行缓慢的方法并认为可以对其进行加速时。它可以让你避免:记录配置文件、等待 Profiler 显示并搜索特定方法的时长。
在你的终端和浏览器控制台中打印时长¶
你可以使用 Performance
API,如下所示:
let start = window.performance.now();
// Run the code you want to measure
// Once it is done, do:
console.log("my function took", window.performance.now() - start, "ms");
使用标记¶
Performance API 还允许记录标记,如下所示:
window.performance.mark("my-function-start");
// Run the code you want to measure
// Once it is done, do:
window.performance.measure("my-function", "my-function-start");
此标记将出现在 profiler.firefox.com 的 Marker Chart
部分的 UserTiming
行中:
你可以双击它,使 profiler.firefox.com 在此特定时间点显示记录,并且调用树将只显示在此测量期间执行的内容。
快速原型设计¶
有时,找到速度慢的原因的最佳方法是逐个注释掉代码块,直到找到罪魁祸首。然后专注于它。
没有什么比花费很长时间重构一开始并不慢的代码更糟糕的了!
评估你的改进¶
一旦你有了你认为可以提高性能的补丁,你必须评估它是否真的提高了性能。
记录另一个配置文件¶
比较两个配置文件,一个没有你的补丁,另一个有你的补丁。然后查看调用树是否报告了显著差异。
在新的配置文件中,你的修复导致函数调用完全消失。例如,你正在加载一个大型模块,并且你得到了
require("my/big/module")
调用的帧,并且不再看到它。使用你的补丁,相同的函数调用减少了 xxx 毫秒。
这个 netmonitor 中模块的延迟加载 是一个很好的例子。在没有此补丁的情况下,App.js 在 91ms 内加载,并加载 MonitorPanel.js 和 StatisticsPanel.js 作为依赖项:
使用此补丁,App.js 在 47ms 内加载,并且只加载 MonitorPanel.js:
它突出了
我们不再加载 StatisticsPanel,
App 加载速度更快。
运行性能测试¶
查看是否有任何子测试报告了改进。确保改进是有意义的。例如,如果测试速度提高了 50%,那么你可能破坏了性能测试。如果测试在完成所有操作执行之前不再等待所有操作完成,则可能会发生这种情况。
要将你当前的补丁推送到 try,请执行
./mach try fuzzy --query "'linux 'damp" --rebuild 5
它将在你的终端中打印一个指向 perfherder 的链接,例如:https://treeherder.mozilla.org/perf.html#/comparechooser?newProject=try&newRevision=9bef6cb13c43bbce21d40ffaea595e082a4c28db 运行性能测试需要时间,因此你应该在 30 分钟到 2 小时后打开它以查看结果。有关 PerfHerder/try 的更多信息,请参阅 DAMP 性能测试。
让我们看看如何解读实际的真实 Perfherder 结果集
这些结果与 netmonitor 中模块的延迟加载 相关。有趣的是,此补丁是一种权衡。它通过在打开时阻止加载许多模块,从而使 netmonitor 打开速度明显加快。但它使页面重新加载速度稍微变慢,因为一些以前在 netmonitor 打开期间加载的模块现在必须在页面重新加载期间加载。