我在网上浏览时发现,两年多来我们没有一个不错的JavaScript框架性能大赛。因此,在2020年总结之前,让我们在将这些库相互抗衡中获得一些乐趣。
如何采用20个最受欢迎的JavaScript框架,并使用JS Framework Benchmark使其并驾齐驱?
免责声明:此比较在整个过程中很有趣,也可能具有教育意义。和往常一样,这里的每个库对于大多数事情来说都足够高效。如果有什么要强调的是,性能可以来自多种不同的技术。虽然您可以将其用作参考,但您应该独立验证各个用例的性能。您可以在这里找到最新的官方结果。如果您想进一步了解此基准测试的内容,请在此处发布指南。
还值得一提的是,我是Solid Framework的作者。因此,我不能在这里表现出任何偏见。但是我打算让这些数字在很大程度上说明自己。撇开所有这些,享受比较。
我已经采用了JS框架基准测试的最新Chrome 87 监控结果。它们在Fedora 33下的Core i7 Razor Blade 15上运行,且缓解措施已关闭。
我过滤掉了所有有问题的实现,然后获得了Github星级的前20个库。对于具有多个版本的库,我没有使用第三方库就获取了它们的最新版本和性能最高的变体。
1. Vue (177k)
2. React (161k)
3. Angular (68.9k)
4. Svelte (40.5k)
5. Preact (27.9k)
6. Ember (21.7k)
7. HyperApp(18.2k)
8. Inferno (14.6k)
9. Riot (14.4k)
10. Yew (14.2k)
11. Mithril (12.5k)
12. Alpine (12.4k)
13. Knockout (9.9k)
14. Marko (9.9k)
15. lit-html (6.9k)
16. Rax (7k)
17. Elm (6.2k)
18. Ractive (5.8k)
19. Solid (4.7k)
20. Imba (4.1k)
注意:我将把LitElement实现用作lit-html示例,因为标准示例已被标记为问题。开销应该最小,因为它是包装在单个Web组件中的原始lit-html。
这是当前Web开发生态系统中相当不错的一部分。尽管Github Stars并不是全部,但在比较中有100多个库,因此我需要标准来选择竞争者。
每个库将在3个类别中进行比较:DOM性能,启动指标和内存使用情况。此外,我将框架分为4组,以将它们与原始性能同级进行最佳比较。但是,我将在所有三个方面对库进行排名。
在每个组中,将存在参考Vanilla JavaScript条目。使用所有最佳技术,此实现都经过了最佳化以达到最佳性能。它将作为所有比较的基准。
因此,让我们开始吧。
这是最大的组,由一些最受欢迎的库组成。还有许多来自Facebook,google,eBay和Alibaba等公司支持的公司。这些库要么在性能上较少关注某个方面,要么在某一方面强调性能,而在其他方面则受苦。
> Group 4 Performance
这里有很多红色和橙色,但请记住,这些库平均仅比我们在此处使用的痛苦手工制作的命令式Vanilla JavaScript示例慢大约2倍。400ms与200ms有何不同?
在原始性能方面,React是该包的领导者。考虑到架构的差异性,尽管它从未间断令人惊奇,但React,Marko,Angular和Ember的整体距离有多近。仍然是React,这是React Hooks的实现,在这里是领导者。对于所有指向额外的函数创建并坚持使用类的人来说,性能参数不在您身边。React Hooks是使用React的最高效的方法。
这里的大多数库要么简单的列表排序导致交换行性能确实很差,要么创建成本很高。Ember是这种情况的极端案例,因为它的更新性能比该组中的其他成员要好得多,但在某些最坏的情况下却是创建过程。
最慢的库(Knockout,Ractive和Alpine)都是具有类似架构的细粒度反应库。Knockout和Ractive(也由Svelte的作者Rich Harris撰写)来自2010年初VDOM库主导之前。我还怀疑Alpine是否期望使用其JavaScript方法来渲染1万行。在比较之后,我们将看不到另一个纯粹的细粒度反应库。
接下来,我们将主要根据库捆绑软件的大小来比较类别的启动指标。
> Group 4 Startup
此处订单变化很大。在Alpine性能最差的地方,我们可以看到它具有最小的捆绑包大小和最快的启动时间。Marko(来自eBay)紧随其后,其次是Rax(来自阿里巴巴)。所有这三个库都是为服务器端渲染而构建的,主要是通过更轻松的客户端交互来实现的。这就是为什么他们要进入第4组才能获得出色的表现,但却领先于这里的原因。
表格的后半部分是我们在基准测试中拥有的最大的捆绑软件,以Ember结尾,是任何其他实现的两倍以上。我不知道为什么要花费超过半兆字节才能呈现此表。但这确实会损害启动性能。
我们要看的最后一类是内存消耗。
> Group 4 Memory
内存往往会反映出我们已经看到的模式,因为它会对性能产生重大影响,而大型库往往会使用更多模式。Alpine,Marko和React引领潮流。老化的细粒度反应库使用最多的Ember。Ember是巨大的。仅在页面上渲染6个按钮之后,它已经使用了比Vanilla在整个套件中要使用的更多的内存。
通常,该组在GitHub上代表30万颗星,可能是NPM下载量的最大部分,但Marko和Alpine在此人群中的平均排名最高。在性能方面,React排名第三,仅次于他们。
这是我们拥有钛白粉比例框架的组,而我们的旧React库也已经消失了。让我们继续乐观一些。
在这些框架中,您可以知道已经考虑了性能。他们意识到规模,并且在创建和更新成本之间找到了平衡。我们看到了各种各样的方法。Yew中的一个Web Assembly框架(用Rust编写),LitElement中的一个Web组件。
事不宜迟,让我们看看他们的做法。
> Group 3 Performance
分数已经提高了一点,我们看到的差距甚至更大。Preact是该组中性能最高的,仅增加了LitElement。Vue 3和Riot捆绑在一起,这两个库都位于中间,它们的历史都包括反应性和VDOM。Mithril是最早将性能放在首位的VDOM库之一,Yew是唯一的WASM库尾部。
在性能方面,所有这些库都是相似的。在这堆中没有纯的反应库。它们都使用自顶向下的呈现方式,无论是VDOM还是简单的Tag Template Literal diff。与上一组相比,它们的对帐清单更智能(请参阅交换行性能)。但是,大多数仍然具有某些最慢的选择行性能。
Yew是例外,但在其他方面则较慢。让我们看看其余的测试是否有帮助。
> Group 3 Startup
情况有所改观,但在启动指标方面,Preact仍然处于领先地位。Yew是这一堆中唯一真正的大型库。WASM库的确偏大。
再次,我们看到一种结果配对。Vue是Yew最大的第二名。Preact和Riot非常紧凑。Mithril和LitElement在中间
Preact是React的4kb替代品,绝对是我们迄今为止所看到的最小的库。但是最小的库仍在继续。尽管如此,这个范围内的任何库都不应该太关注它们的包大小。
> Group 3 Memory
Yew这次赢了。在所有经过测试的框架中,它具有最小的内存占用量。WASM库在这里往往做得很好。其他都非常接近。Mithril和普瑞特Preact是最差的,但不是很多。
这里没有太多可拉的东西。您可能会认为LitElement示例可能比其他非红豆杉库更轻巧,因为它没有像其余的那样使用虚拟DOM。但是,正如我们将在以后看到的,VDOM并不意味着更多的内存。
Riot和Preact的平均排名最高,其次是LitElement,排名第三。Riot虽然没有脱颖而出,但在这个小组中没有弱点,因此取得了胜利。但是,对于这些框架中的任何一个都很难失望。借助WASM和Web组件,它们代表了许多人认为Web的未来。
但是我们还没有完成。下一组代表对网络未来的不同想法。输入编译器…
这一组是激烈的竞争。我们拥有大多数被称为编译语言的库。每个都有自己的风味。我们拥有不变的结构化Elm,受Ruby启发的Imba和"消失的" Svelte。
注意:引起我注意的是,并不是每个人都熟悉Svelte以前的"消失的框架"绰号。它描述了从输出中基本进行自我编译的能力。我不是在建议Svelte去任何地方。对带来困惑感到抱歉。
奇怪的是HyperApp,它与其他应用程序完全相反。没有编译器。没有模板。只需h函数和一个最小的Virtual DOM。
猜猜这将如何发展?
> Group 2 Performance
好吧,最小的虚拟DOM胜出。与最近的言论相反,事实证明虚拟DOM不仅是性能不佳的秘诀,而且编译并没有使其他库受益。
在已编译的库中,我们实际上看到了3种不同的方法来渲染所有具有大约相同的平均性能。Imba使用DOM协调(更接近我们之前看到的LitElement),Elm使用虚拟DOM,最后一个Svelte使用组件反应系统。
您应该注意,虚拟DOM库的选择行最差,因为这是其额外工作所显示的。但是这些库还具有更快的初始渲染。如果您仔细观察到目前为止的结果,您应该注意到Virtual DOM库与Reactive库之间的共享特性。但除此之外,性能还很严格。
因此,让我们继续。我们的编译器如何调整启动时间/捆绑大小?
> Group 2 Startup
好吧,正如您所看到的那样,这个小的虚拟DOM库不仅性能更高,而且比其他的更小。实际上,HyperApp是我们所有库中最小的实现。编译器无法赢得成功。
它和Svelte都比我们的Vanilla JavaScript参考构建小。那怎么可能?以一种更可重用的方式编写更少的代码来编写抽象。Vanilla JS实现针对性能而非大小进行了优化。
Elm在这个群体中仍处于规模竞争中。但是,Imba开始进入某些第4组库的范围。
好了,留下记忆。编译器大放异彩的最后机会。
> Group 2 Memory
内存接近,几乎是平局,但是Svelte最终为编译器赢得了胜利。对虚拟DOM的一些甜蜜的报复显示它比它更小,更快。
老实说,所有这些库都具有出色的内存配置文件。现在应该很清楚,更少的内存和更好的性能之间的关系。
不相信炒作吗?
不。更多的事情比表面上看起来复杂。精心设计的系统,无论是运行时还是编译时,或者无论采用何种技术方法,都可以制成高性能的系统。
HyperApp是该组的明显赢家,其后是Svelte,其次是Elm和Imba。通过这种对性能的专注,您知道这些库在大多数情况下都可以提供,并且始终显示在基准测试的顶部。
那还剩下什么?
如果我告诉您,声明性JavaScript库对它们的性能如此有信心,就不用担心原始WASM,Web Worker或您使用的任何技术,该怎么办。欢迎来到…
在某一时刻,它可能被称为"超快",我相信它曾经是这些库的口号之一。如果您要跟踪的话,只剩下2个库了。实际上,这类库中有少数几家不断推陈出新。但是在流行的中只有2种。它们平均比原始的手工优化Vanilla JS慢20%。
这是要看的东西。在这里,我们有2个库,如果查看它们的代码,它们可能被视为同级库,但使用的方法完全不同。Inferno是世界上性能最高的虚拟DOM库之一。在最出色的5个执行者中,有3个是虚拟DOM库。选择行测试的速度下降可以视为证据。
另一方面,Solid使用细粒度的反应性,例如第4组中最慢的旧库。重新出现此技术的位置很奇怪,但正如我们所见,Solid解决了它们的弱点。创建时间与更新时间一样快。与Vanilla JavaScript的5%差距令人难以置信。
奇怪的是,Inferno和Solid的共同点是JSX模板和React受启发的API。对于所有其他具有经过优化的自定义DSL的库,也许您不会期望在性能的顶峰找到任何东西。但是,正如HyperApp所示,某些事情对性能的影响比人们想象的要小。
> Group 1 Startup
Solid将HyperApp和Svelte作为第三个库加入,其库比Vanilla JS实现小。但是Inferno也不是懈怠。
似乎性能库较小时,有时添加更多代码可以提高性能。更好的列表协调算法,更明确的防护措施,更精细的更新。
Inferno可能比前几组中的某些库更大,但它仍然是一个10kb以下的库,并且几乎在所有性能上均不如预期。
> Group 1 Memory
在那里。除了Yew及其对WASM的使用以外,它们是整个竞争中最低的内存消耗框架。考虑到他们的表现,这并不奇怪。
这种内存消耗数字反映了对对象的非常仔细的考虑,并创建了闭包。其中很多确实来自两个库都进行的定制JSX转换。
内存性能的提高对Solid尤为重要,因为Solid与大多数细粒度的反应式库一样,都将CPU开销换成了内存消耗。在这种比较中,能够征服内存开销是Solid如何采用与大多数最慢的库类似的技术并使之成为最快的方法的很大一部分。
天空是极限。
…或者说Vanilla JavaScript是。但是我们这里的声明式库性能如此之差,您永远都不会知道它们之间的区别。当使用DOM时,我们需要认真考虑,许多不同的技术可以有效地渲染DOM。
我们在这里看到它。Solid在十年前就被认为是古老而缓慢的技术,夺得了性能冠军,而Inferno再一次证明了虚拟DOM不能高效完成的工作。
在构建JavaScript前端时,我们有很多选择。这只是快速浏览框架带来的性能开销。当涉及到应用程序中的实际性能时,用户代码具有更大的影响。
但是,我真正想在这里打动的是,测试您的解决方案并了解性能是很重要的。现实总是与营销不同。虚拟DOM不能保证很慢。不能保证编译器会产生最小的捆绑包。自定义模板DSL不能保证是最佳的。
最后,我将为您提供完整的表,将所有库一起显示。仅仅因为库快要结束了,并不一定意味着它很慢,但是与这些竞争激烈的竞争对手相比,它的得分更差。
单个图表中的所有框架。
所有结果都添加到一个列表中(第1名获得20分,最后1名获得分)。在平局的情况下,性能优先。
1. Solid (57)
2. HyperApp (54)
3. Inferno (51)
4. Svelte (51)
5. Elm (46)
6. Riot (40)
7. Preact (39)
8. Imba (36)
9. lit-html (36)
10. Yew (32)
11. Vue (29)
12. Mithril (29)
13. Marko (28)
14. Alpine (28)
15. React (19)
16. Rax (16)
17. Angular (12)
18. Knockout (11)
19. Ractive (8)
20. Ember (6)
特别提及AJ Meyghani在2018年的比较,这启发了这篇文章。
(本文由闻数起舞翻译自Ryan Carniato的文章《JavaScript Frameworks, Performance Comparison 2020》,转载请注明出处,原文链接:https://medium.com/javascript-in-plain-english/javascript-frameworks-performance-comparison-2020-cd881ac21fce)