通过缓存原始视图模块查找来优化FCP/LCP

我正在尝试通过这两个 PR 来改进 First Contentful Paint (FCP) 和 Largest Contentful Paint (LCP):

我对这些更改的实际影响非常感兴趣——所以请尝试一下并提供一些反馈。

当然,任何关于测试、重构和测试覆盖率的帮助都非常受欢迎。

11 个赞

第一个看起来是一个简单的优化,我认为这是有意义的,@david@eviltrout 花时间优化了这部分,所以我非常想知道他们对此的看法。

第二个感觉长期来看有点脆弱,我完全理解优化的愿望,但这让我有点担心,因为它将是我们以后需要维护的一个区域。

5 个赞

你好 @rrit - 感谢你的 PR。第一个听起来是个不错的改进。你是否能够衡量性能影响?它节省了多少时间?

正如 @sam 所说,第二个的可维护性有点令人担忧。它看起来是从 Ember 源代码复制/粘贴的吗?你是否为了提高性能而更改了某些内容?

4 个赞

lookupView-patch

现在通过 Map 实现,而不是 Array

lookupView 在应用程序启动时花费的时间 - 开发实例:

节省的时间:约 115 毫秒

这会将 appendOutletView 内部花费的时间从 1.083 毫秒减少到 946 毫秒 - 开发实例。


patch on raw handlebar helpers

是的,实际上是复制粘贴,只有一个更改:使用廉价的 isPath 检查。

      // replaces @ember/-internals/utils isPath
      // @see: https://github.com/emberjs/ember.js/blob/3537670c14883346e11e841fcb71333384fcbc87/packages/%40ember/-internals/metal/lib/path_cache.ts#L5-L7
      // @see: https://github.com/emberjs/ember.js/blob/255a0dd3c7de1187f4a2f61a97cf78bfff8f66a8/packages/%40ember/-internals/glimmer/lib/utils/bindings.ts#L70
      let isPath = context.indexOf('.') > -1;

例如,renderTopicListItem 最终会触发许多 _getPath 调用(还可以节省 50-100 毫秒):
Firefox Profiler (renderTopicListItem_getPath 的 callstack 过滤)

也许昂贵的 _getPath 调用应该在 Ember.js 中优化,而不是在 Discourse 中。


并查看 Firefox Profiler 以深入了解 JavaScript 执行:

4 个赞

谢谢您的补丁。第二个补丁似乎有点脆弱。

您的基准测试是在开发模式还是生产模式下运行的?Ember 在这两种模式下的性能差异很大。

2 个赞

@david 找到了一种解决此问题的好方法 - 请参阅他在 github 上的评论

在 Ember 的“production”构建中,“latest”网页上调用 renderTopicListItem 的时间从 348 毫秒减少到 201 毫秒。

之前的基准测试仍在开发模式下运行。


如何在 Ember.js 生产模式下运行基准测试?

# 在生产模式下启动 ember
d/ember-cli server --environment="production"
2 个赞

不幸的是,我无法复制这种显著的速度提升。在 Firefox 和 Chrome (macOS) 上,我没有看到任何可衡量的改进。Chrome 在 renderTopicListItem 上花费约 23 毫秒。Firefox 约 30 毫秒。在较旧的 Android 设备 (Pixel 3) 上,我看到约 108 毫秒。更改前后数字似乎没有变化。

顺便说一下,我是通过使用 performance API 来测量这些数字的。我在 renderTopicListItem 的开头添加了 performance.mark("rtli-start"),然后在结尾添加了 performance.measure("rtli", "rtli-start")

然后,我关闭开发者工具并禁用浏览器插件(开发者工具和浏览器插件会显著影响渲染性能)重新加载浏览器。加载完成后,打开开发者工具并运行此代码来汇总测量结果:

performance.getEntriesByName("rtli").reduce((v, m) => v + m.duration, 0);

我们肯定会合并这项更改——这显然是一个更好的实现。但我不太确定它是否会给我们带来可见的渲染性能差异 :thinking:

7 个赞

我仍然可以在 Firefox 的隐私模式(Linux)中使用性能 API 重现性能优势。

正在测试 http://localhost:4200/latest
renderTopicListItem 的耗时从约 290 毫秒降至约 190 毫秒。

我的 Discourse 测试实例包含许多带有许多回复和许多不同作者的主题 - 数据是从生产实例中提取的。这导致需要渲染大量元素。
也许这是我们基准测试的差异所在?


视口下方内容的预渲染

Discourse 在“latest”页面上预渲染 30 个主题。然后内容首次显示(FCP)。视口上方只有约 12 个主题可见。

主题页面也一样:预渲染 20 篇帖子,但视口上方最多只显示 6 篇单行帖子。

这可能是 FCP 的另一个优化点。

1 个赞

您介意分享一下 Firefox 和操作系统版本吗?290 毫秒的数字几乎是 2018 年 Android 设备的 3 倍,这有点令人惊讶。

是的,这也许能解释一些差异。在我的例子中,我使用来自 Meta 的实时数据运行了它们:

bin/ember-cli --environment production --proxy https://meta.discourse.org

是的,这是一个可能的改进。但是,我们需要非常小心,确保布局和/或滚动不会跳动(例如,如果用户在滚动到一半时刷新页面)。“below the fold”的定义也因设备/浏览器/主题而异。

3 个赞

代理到 meta.discourse.org

遗憾的是,使用代理运行 ember 对我来说失败了:

d/ember-cli --environment production --proxy https://meta.discourse.org

http://localhost:4200/

Discourse Build Error

Error [ERR_TLS_CERT_ALTNAME_INVALID]: 主机名/IP 与证书的 altnames 不匹配:
主机:localhost. 不在证书的 altnames 中:DNS:*.cdck-prod-meta.discourse.cloud

http://127.0.0.1:4200/

Discourse Build Error

Error [ERR_TLS_CERT_ALTNAME_INVALID]: 主机名/IP 与证书的 altnames 不匹配:
主机:meta.discourse.org. 不在证书的 altnames 中:DNS:*.cdck-prod-meta.discourse.cloud

用于基准测试的系统

摘自 Firefox about:support

名称 Firefox
版本 95.0.2
Build-ID 20211219102529
Distributions-ID canonical-002
用户代理 Mozilla/5.0 (X11; Linux x86_64; rv:95.0) Gecko/20100101 Firefox/95.0
操作系统 Linux 5.10.0-0.bpo.9-amd64 #1 SMP Debian 5.10.70-1~bpo10+1 (2021-10-10)
操作系统主题 Adwaita-dark / Adwaita
应用程序文件 /snap/firefox/777/usr/lib/firefox/firefox
名称 Firefox Developer Edition
版本 96.0b10
Build-ID 20211228195952
Update-目录 /opt/firefox-dev-autoinstall
Update-通道 aurora
用户代理 Mozilla/5.0 (X11; Linux x86_64; rv:96.0) Gecko/20100101 Firefox/96.0
操作系统 Linux 5.10.0-0.bpo.9-amd64 #1 SMP Debian 5.10.70-1~bpo10+1 (2021-10-10)
操作系统主题 Adwaita-dark / Adwaita
应用程序文件 /opt/firefox-dev-autoinstall/firefox-bin

摘自 Chromium chrome://system/

CHROME VERSION 90.0.4430.212 built on Debian 10.9, running on Debian 10.11
OS VERSION Linux: 5.10.0-0.bpo.9-amd64

操作系统版本:

# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 10 (buster)"
NAME="Debian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=debian
2 个赞

重构的拉取请求现已合并:

感谢你提出这个问题,@rrit - 这是一个很好的改进!

5 个赞

此主题已在 9 小时后自动关闭。不再允许回复。