发布于 2026-01-06 1 阅读
0

理解 JS 框架基准测试:基准测试的意义何在?理解测试、查看结果、全面解读

理解 JS 框架基准测试

那么,有没有基准指标呢?

了解考试

查看结果

从更宏观的角度来看

你听说过一家新图书馆,并决定去了解一下。或许你需要对一项你还没机会使用的技术做出决定。你读过一些文章,也看过一些社交媒体上的推荐,但现在你需要尽快弄清事情的本质。

你可以浏览 NPM 下载页面和 Stack Overflow 来了解整个生态系统。你可以查看 GitHub 来了解问题是如何解决的,并通过星标数量来衡量其受欢迎程度。但如果你想深入了解库或技术本身呢?

那么,有没有基准指标呢?

今天我想介绍一下我认为是目前最好的 JS UI 框架基准测试套件——JS Framework Benchmark。它将近百个不同的库与它们各自的实现进行比较,这些实现通常由作者/维护者亲自编写或维护。更重要的是,虽然测试场景有些夸张,但它模拟的是最终用户在处理列表时的操作。这些操作正是用户在日常应用中经常会用到的。

然而,这并非您探索之旅的起点。基准测试只是众多工具之一,它只能反映问题的一方面。幸运的是,市面上有一些工具可以帮助您在深入研究之前了解大致情况。

1. TodoMVC(http://todomvc.com/

这可能是任何 JS 库都必须制作的最重要的演示。它是最简单的示例,模板和视图都是标准化的,并且提供了现成的 CSS。

您可以浏览代码,了解它的全部内容。如果您无法接受 TodoMVC 的实现方式,您可能也不会喜欢这个库。

最棒的是,几乎每个 JS 库都有相应的实现。快速搜索一下,通常就能找到你能想到的几乎所有库。

2. 真实世界演示(https://github.com/gothinkster/realworld

这比 TodoMVC 示例有了显著的进步。我们现在有了一个真正的应用程序。当然,它规模不大,但即便如此,这些实现仍然需要开发者花费数周时间才能完成。尽管如此,许多库维护者仍然不辞辛劳地向这个演示提交代码。目前市面上已经有几十种不同的实现版本。

这个演示版本严格按照规范编写,所有样式和视图模板结构都已设置好。这使得每个实现都非常具有可比性。

它甚至能更好地表明你是否喜欢这段代码。你可以开始了解构建应用程序的特点,开始发现一些模式和生态系统,还可以开始了解诸如初始加载性能和包大小之类的信息。


了解考试

JS框架基准测试包含一系列测试,涵盖性能、加载时间和内存使用情况等多个方面。它本质上是一个功能强大的 TodoMVC 示例,测试了所有常见的列表操作,规模可达数千行。

我将从当前结果页面中选取一些库来解释如何解读这个基准测试。

所有分数下方括号内均包含一个相对于最快实现的归一化分数。最后一行使用这个归一化分数计算几何平均值,从而对库进行排名。

分类说明:我建议重点关注带键结果,因为虽然不带键结果在少数特殊情况下有优势,但通常被认为是一种危险的做法。更多信息请点击此处

表现

替代文字

前 9 项测试侧重于性能。它们在 Chrome 驱动程序上运行,CPU 使用率受到限制,类似于 Lighthouse 移动测试。这突出了在低端设备上运行的开销。此外,所有测试都在页面初始加载后运行,因此不受网络/数据包大小的影响。后续还有其他测试用于衡量这些因素。

1. 创建行

创建 1000 行。此测试衡量渲染 8000 个 DOM 元素的成本。每个库都会创建相同的 8000 个元素,因此这可以很好地反映纯粹的创建时间。而设置绑定或创建库将使用的任何其他结构的开销则体现在这里。

2. 替换行

与第一个测试类似,但这个测试会替换已渲染的 1000 行数据。此测试结合了创建时间和处置开销。虽然它同时包含了这两项开销,但其最大的价值在于了解当页面上的大部分内容发生变化时,库的性能表现。对于表格而言,除了创建所有新内容之外,库还必须确认每一行数据都已被删除。

3. 部分更新

这是每隔 10 行进行的嵌套数据更新。为什么是每隔 10 行?这样既能保证有足够的变更可供追踪,又能确保大部分行不会被更新。根据所使用的库,有些库可以只检测到特定数据的变化,而有些库则需要运行所有数组比较代码。此测试是衡量动画性能和深度嵌套数据结构开销的最佳指标。简而言之,此测试旨在检验库模板的动态部分。

4. 选择行

此测试跟踪两行之间的选择状态变化。它使用单个selectedRow状态实现。它测试了在所有行上委托状态更改的成本。与库检查每行是否被选中的开销相比,这里的 DOM 操作微不足道。测试 3 很好地指示了理想的局部更新性能,而此行则显示了简单局部更新的性能成本。

注意:如果您看到一些库被标记为存在问题,绝大多数都是相关的库,它们为了实现预期功能,想出了巧妙的方法来绕过这个测试。有时这是迫不得已,因为这些库本身没有进行声明式更新的机制。

5. 交换行

此测试将第 2 行与第 999 行交换。这是唯一一个纯粹测试库进行列表差异比较开销的测试。遗憾的是,此测试过于简单,无法真正展现差异比较的性能,并且只能提供二元结果。库要么使用简单的迭代,要么使用智能迭代。这可能并不重要,因为结果取决于行数,而如果您有这么多行,您可能应该考虑其他方法。

6. 删除行

此测试从包含 1000 行的列表中删除一行。此测试可能是变化最小的测试,因为它更多地测试浏览器的布局偏移(所有行向上移动),而不是库的任何开销。

7. 创建多行

这个测试和第一个测试类似,只不过这次使用了 10,000 行数据。没错,就是 80,000 个 DOM 元素。虽然一个复杂的 UI 可能只有 8,000 个元素,但这个数字完全是荒谬的。这个测试和第一个测试一样,主要关注的是创建操作。它更容易受到内存开销的影响,而且对于效率较低的库来说,扩展性会更差。

8. 添加到大列表

此测试在先前已渲染的 10,000 行数据的基础上,再添加 1,000 行数据。这旨在测试当列表已包含大量数据项时,进行差异比较的处理开销。许多库创建数据很快,但比较数据却慢得多。此测试旨在检验随着页面规模的扩大,库执行增量添加操作的能力。

9. 清除行

此操作一次性删除所有 1000 行数据。这体现了库清理代码的开销。通常很容易识别出所有需要清除的行(data.length === 0),但使用方法优化更新的库需要在此处进行清理。由于浏览器需要进行垃圾回收的内存更多,因此内存使用情况对本次测试影响很大。与同时进行数据创建的测试 2 相比,本次测试能更直接地衡量这种开销。

创业指标

替代文字

该基准测试还使用 Lighthouse 的移动模拟功能来测试库的加载速度。这些结果只是近似值,但这一部分确实提供了一些有用的信息。

1. 持续互动

这是一个保守的 TTI 测试方法,它会等待 CPU 空闲 50 毫秒。除非你的库非常庞大,否则这里的分数差异并不大,而且似乎主要与包的大小成正比,WASM 库除外,它们似乎不受影响(Blazor 除外)。我推测 JS 解析时间是这项测试的重要组成部分。

2. 脚本启动时间

这项测试衡量的是评估页面脚本所花费的时间,可能是整个基准测试中最不实用的一项,因为它受限于帧数(最佳成绩为 16 毫秒)。虽然有些库在这里的表现更差,但处理速度也可能因是否在单帧内完成而有所不同。脚本大小与处理速度之间存在一定的相关性,但并非绝对。

3. 总千字节重量

这衡量的是所有资源的总大小,包括用户代码、HTML 和 CSS。这很有用,因为它显示了实际构建大小与打包大小的对比。像 Preact 这样的库,gzip 压缩后可能只有 4KB,但一个更频繁地使用 tree shaking 的库,理论上大小可能是它的两倍,但实际大小却会小好几 KB。有些库甚至比原生 JavaScript 实现还要小。

记忆

替代文字

这或许是我们最难做出判断的指标,但它有助于描绘整体性能图景。至少,它能帮助不少库作者发现库中存在的严重内存泄漏问题。而且,它或许还能对低配置设备起到一定的限制作用。

1. 就绪内存

这是页面加载完成后立即读取的内存量。由于页面上只有几个按钮,所以内存占用很低,大多数库在这方面的表现都差不多。

2. 运行内存

这是创建前 1000 行数据后立即进行的内存读取(与性能测试 1 相同)。这是所有额外 DOM 节点和动态库构造的开销。它是衡量库运行时性能的首要指标。

3. 每隔 10 行更新一次

与性能测试 3 相同,但这次我们观察的是部分更新带来的内存开销。这主要是由于新字符串值的分配造成的,但您也会首次看到库的动态差异比较机制带来的内存开销。

4. 替换行

与性能测试 2 类似,此测试会将 1000 行数据替换 5 次。你可能会认为内存占用应该与运行内存测试类似,但实际上,即使是使用 VanillaJS,在创建和清除至少一次数据时,也总会存在一些额外的开销。这是一个很好的内存泄漏检测测试。

5. 创建/清除行

与性能测试 9 类似,此测试会创建并清除 1000 行数据。你可能会认为,理想情况下,这应该能使我们的内存使用量恢复到基准水平。但正如 VanillaJS 所显示的那样,即使使用 VanillaJS,仍然存在额外的内存开销。库的内存使用量越接近 VanillaJS,它们在自身清理内存方面的效率就越高。


查看结果

此基准测试可让您将搜索范围缩小到测试、实现,甚至不同的视图模式。比较模式尤其有用,因为它能以可视化的方式显示统计显著性。

替代文字

这里我将选定的库与 Svelte 进行比较。你可以看到,性能相近的库用白色单元格表示;性能显著更优的库用绿色单元格表示;性能显著更差的库用红色单元格表示。

每个测试都不一样,所以它可以帮助你获得更全面的了解。在很多方面,不同库在许多指标上的性能都比较接近,因此通常需要一段时间才能发现性能上的显著差异。只有到了 Angular,我们才会发现性能明显下降;而到了 Solid,我们才会发现性能明显提升。

此外,箱线图视图可以很好地帮助绘制方差图。这对于分析单个测试并了解其结果的一致性非常有用。

替代文字


从更宏观的角度来看

基准测试只是问题的一方面。我们应该始终以怀疑的态度看待它们,但不应轻视它们。我认为,当你遇到维护良好且设计精良的基准测试时,你可以从中了解很多关于库的运行情况。

像JS Framework Benchmark这样的基准测试在某些方面更加严苛,而在另一些方面则更为宽松。该测试很大程度上受限于 DOM 操作,而这些操作实际上只在大型页面导航时才会影响实际应用。鉴于这些实现已经是最优化的,其余的成本则不成比例地与库的执行时间相关。

在实际应用中,用户代码往往才是耗时最长的部分。我们很容易把责任推卸给框架,基准测试也支持这种说法。所以,如果你觉得自己的代码完美无瑕,那就去寻找速度最快的库吧。但实际上,事情远比这复杂得多。

并不存在真正意义上的“真实世界基准测试”,大多数尝试都略显肤浅,例如只关注页面初始加载速度。不过,如果您正在寻找基准测试工具,那么这款算是目前市面上最好的之一。

文章来源:https://dev.to/ryansolid/making-sense-of-the-js-framework-benchmark-25hl