写点什么

JS 框架性能对比:Solid 高居榜首,Vue、React 和 Angular 竟纷纷跌出前十

  • 2021-01-29
  • 本文字数:5555 字

    阅读完需:约 18 分钟

JS框架性能对比:Solid 高居榜首,Vue、React 和 Angular 竟纷纷跌出前十

之前我在网上闲逛的时候发现了一件事,那就是两年多来都没人做一次高水平的 JavaScript 框架性能对比。所以在 2021 年伊始,我们就来找点乐趣,让这些库好好较量一下吧。本文主要出于娱乐目的,在某种意义上说,会具有一定的参考意义。


该怎么对比呢?那就选出 20 个最受欢迎的 JavaScript 框架,并用 JS Framework Benchmark 来一场针锋相对的大比拼如何?


免责声明:这篇评测主要是出于娱乐目的,可能也会有些实际价值。一如既往,这里提到的每一个库在大多数场景中效率都很高。如果有什么需要强调的话,那就是测出的性能优势可能来自多种不同的技术和技巧组合。虽然你可以将本文当做参考,但你应该自己去验证框架在各个用例中的性能。你可以在这里找到最新的官方成绩对比。如果你想进一步了解这个基准测试,可以参阅我写的这篇指南


还有一点需要提一下,我是 Solid Framework 的作者,因此我免不了会在文章中掺杂一些偏见。但我的打算是尽量让数字说话。了解过这些背景后,就请坐下来欣赏比赛吧。

比赛开始


我用的是 JS Framework Benchmark 中最新的 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. Rax(7k)

  16. lit-html(6.9k)

  17. Elm(6.2k)

  18. Ractive(5.8k)

  19. Solid(4.7k)

  20. Imba(4.1k)


注意:对于 lit-html,我用的是 LitElement 实现,因为标准版标记了一个问题。它的开销应该很小,因为它是包装在单个 Web 组件中的原始 lit-html。


这是当下 Web 开发生态系统中非常优秀的一组选手。尽管 Github 星级并不能完全说明问题,但测试结果里有 100 多个库,因此我需要一个标准来选出参赛者。


每个库都会参与三大类别的对比:DOM 性能、启动指标和内存使用情况。此外,我会将这些框架分为 4 组,这样就能更好地同性能相近的对手对比了。但我也会给出三大类别的总排名。


在每一组中都会有作为参考的标准 JavaScript 条目。这一实现使用了所有最优秀的技术来做优化,以实现最佳性能。它将作为所有对比的基线。


下面就开始比赛吧。

第 4 组——标准性能


这一组选手最多,包括一些最流行的库。还有一些库有 Facebook、Google、eBay 和 Alibaba 等大公司的支持。这些库要么不太关注性能表现,要么就是只关注某一方面的性能,而在其他方面表现不佳。


第 4 组速度成绩


这里有很多红色和橙色块,但请记住,这些库平均只比我们精心优化的命令式标准 JavaScript 参考慢大约一倍。400ms 比 200ms 能慢多少呢?


在纯性能方面,React 在这一组中拔得头筹。但考虑到架构的差异性,React、Marko、Angular 和 Ember 的整体表现竟然会如此接近,这也很让人惊讶。不过 React,具体来说是 React Hooks 实现最后胜出。如果你需要额外的函数创建并坚持使用类,那么就不用对性能抱太大期望了。React Hooks 是使用 React 的最高效途径。


这里的库大都有简陋的列表排序(导致糟糕的行交换性能),或者有很高的创建成本。Ember 就是一个非常突出的典型,因为它的更新性能同组的对手要好得多,但创建性能却是最差的。


最慢的库(Knockout、Ractive 和 Alpine)都有着架构相似的细粒度响应库。Knockout 和 Ractive(也是 Svelte 的作者 Rich Harris 的作品)都起源于 VDOM 库流行之前的 2010 年代初期。Alpine 的那点 JavaScript 方法渲染起来也是够慢的。下一个纯粹的细粒度响应库会在很后面的对比中才会出现。


接下来,我们将主要根据库的打包大小来对比启动指标类别。


第 4 组启动成绩


这里的排名和之前有很大区别。Alpine 的速度表现最差,但我们可以看到它的包最小,启动时间最短。Marko(来自 eBay)紧随其后,接下来是 Rax(来自阿里巴巴)。这三个库都是为轻量级客户端交互的服务端渲染而构建的。所以它们的性能只能排在第 4 组,但启动成绩却在这一组中领先。


表格的后半部分是我们在基准测试中包体积最大的几名选手,其中 Ember 成绩最差,大小是其他任何实现的两倍以上。我不知道为什么要花费超过半兆字节才能渲染出这个表,但不管怎样这都会拖累启动性能。


最后一个类别是内存消耗。


第 4 组内存成绩


内存成绩往往是和之前两类成绩相关联的,因为它会对性能产生重大影响,同时大型库往往会使用更多内存。Alpine、Marko 和 React 位居前三。老旧的细粒度响应库使用的内存最多,Ember 敬陪末座。Ember 太吃内存了。仅在页面上渲染 6 个按钮之后,它用的内存已经比标准参考在整个套件中所用的还要多了。

第 4 组结果


总体来看,这一组库在 GitHub 上总共有 30 万星,可能在 NPM 下载中占据了大部分份额。在这组选手中,Marko 和 Alpine 的平均排名最高。React 排名第三,而速度表现是最好的。


本组中的一些框架在市场份额上遥遥领先,而一些老旧的响应库已经是昨日黄花。接下来我们研究一些表现更好的选手。

第 3 组——重视性能


这一组里的框架可以说在设计时考虑到了性能需求。它们在包大小指标上也下了功夫,并且在创建和更新成本之间找到了平衡。


我们在本组中能看到五花八门的方法。比如 Yew,一个 WebAssembly 框架(用 Rust 编写);LitElement,一个 Web 组件。最近发布的 Vue 3 是这个框架的重大进化,让它走出了第 4 组,开始和一些之前没有遇到过的对手直接竞争。


闲话少提,下面来看看它们的表现。


第 3 组速度成绩


整体分数提高了一些,同组内的差距也大多了。Preact 是本组中速度最快的,LitElement 则以微弱劣势紧随其后。Vue 3 和 Riot 速度相近,都位居中游,它们也都有过响应性和 VDOM 并存的历史。Mithril 是最早将速度放在首位的 VDOM 库之一,而 Yew 作为唯一的 WASM 库落在了最后。


在性能 profile 方面,所有这些库都差不多。这组里面没有纯粹的的响应库。它们都使用自上向下的渲染方式,无论是 VDOM 还是简单的 Tag Template Literal diff 都一样。与上一组相比,它们的列表处理更智能些(参阅行交换性能)。但多数框架的行选择性能还是最低一档。


Yew 是个例外,但它的其它指标都差不少。我们看看其他测试有没有什么不同。


第 3 组启动成绩


情况有所改观,但在启动指标方面 Preact 仍处于领先地位。Yew 是本组中唯一称得上大型库的。WASM 库的确偏大。


这里我们又能看到一些相近的成绩。Vue 也很大,仅次于 Yew。Preact 和 Riot 的表现非常接近。Mithril 和 LitElement 也差不多,都位居中游。


Preact 是 React 的一个 4kb 替代品,它显然是我们目前见过的最小的库,但后面还有更小的呢。不管怎样,本组中的这些库都不需要用户太操心它们的包大小。


第 3 组内存成绩


Yew 这次赢了。在测试过的所有框架中,它的内存占用量最少。WASM 库在这方面往往能做得很好。其他成绩都非常接近。Mithril 和 Preact 是最差的,但落后也不是很多。


这里没有什么特别值得一提的东西。你可能会认为 LitElement 可能比其他库(Yew 除外)更轻巧,因为它没有像其他库一样使用虚拟 DOM。但我们稍后会看到,VDOM 并不意味着就要占用更多内存。

第 3 组结果


Riot 和 Preact 的平均排名最高,其次是 LitElement,排名第三。Riot 虽然没有明显胜出,但在这一组中没有弱点,因此取得了胜利。但是,这些框架中无论选了哪一个都很难会失望。至于 WASM 和 Web 组件,它们代表了许多人心目中 Web 的未来。


但我们还没有完成。下一组代表了对 Web 未来的另一种思考。我们要进入编译器的领域了。

第 2 组——性能冠军


这一组的竞争很激烈。本组中的多数库都被称为编译语言,每种都有自己的风味。这组里有不可变的结构化 Elm、受 Ruby 启发的 Imba 和“正在消失的”Svelte。


注意:我发现,并不是所有人都熟悉 Svelte 以前那个“正在消失的框架”的绰号。这个绰号指的是它从输出中基本编译出自身的能力。我并不是说 Svelte 没希望了,如果造成困扰我很抱歉。


比较特殊的是 HyperApp,它与同组其他选手完全相反。它没有编译器、没有模板。只有 h 函数和一个最精简的 Virtual DOM。


猜猜结果如何?


第二组速度成绩


胜出的竟然是最精简的虚拟 DOM。与最近的流行观念相反,事实证明虚拟 DOM 并不是糟糕性能的代名词,而且编译并没有给其他库带来显著优势。


在编译的库中,我们实际可以看到 3 种不同的渲染方法,平均速度都差不多。Imba 使用 DOM 一致性对比方法(和我们之前看到的 LitElement 很像),Elm 使用虚拟 DOM,排在最后的 Svelte 使用了一个组件响应系统。


你应该注意的是,虚拟 DOM 库的行选择性能最差,体现出了它们的额外开销。但这些库还有着更快的初始渲染速度。如果你仔细观察到目前为止的结果,应该能注意到虚拟 DOM 库与响应库之间共有的这一特性。不过在其他指标上大家的速度都差不多。


所以我们继续分析。这些编译器的启动时间/包大小怎么样呢?


第 2 组启动成绩


如你所见,这个小巧的虚拟 DOM 库不仅速度更快,包也比其他库更小。实际上,HyperApp 是我们所有库中最小的实现。编译器在包大小方面没法取胜。


它和 Svelte 都比我们的标准 JavaScript 参考构建更小。为什么会这样呢?因为它们的抽象是以一种更加可重用的方式编写的,所以用到的代码更少。标准 JS 实现的优化主要针对性能而非包大小。


Elm 的包大小在本组中表现也不错。但是,Imba 的成绩开始落到了第 4 组的水平上。


剩下的就是内存占用了,也是编译器大放异彩的最后机会。


第 2 组内存成绩


内存结果非常接近,几乎是平局,但是 Svelte 终于为编译器赢得了胜利。这是对虚拟 DOM 的一场成功复仇,虽然前者速度更快,体积更小。


老实说,所有这些库都有出色的内存 profile。现在我们应该很清楚地看到更快的速度与更低的内存占用之间的关联了。

第 2 组结果


不要相信宣传口号?


对。很多事情比表面上看起来复杂很多。精心设计的系统,无论是运行时还是编译时,或者无论采用何种技术方法,都可以获得高性能的表现。


HyperApp 是本组的大赢家,紧随其后的是 Svelte,然后是 Elm 和 Imba。它们都对性能非常重视,所以你可以期望这些库在大多数情况下都可以提供最顶尖的性能表现。


后面还有什么结论呢?


我可以告诉你,声明式 JavaScript 库的性能也可以非常出色,不管是纯粹的 WASM、Web Worker 或随便什么技术它都不会怕的。于是我们来到了……

第 1 组——顶尖高手


某种程度上本组可以被称为“快如闪电”,我想这些库也用过这个口号。其实你留心的话,会意识到剩下的选手只有两位了。实际上,这个层次上有一些库在不断创造新的纪录,但其中只有两个库比较流行。它们比手工优化的纯 JS 平均要慢 20%。


第 1 组速度成绩


结果值得研究一番。这里我们有两个库,查看它们的代码会发现,虽然它们的速度相近,但使用的方法完全不同。Inferno 是业内性能最高的虚拟 DOM 库之一。也就是说在速度最快的 5 名选手中有 3 个是虚拟 DOM 库。行选择测试的速度下降可以视为证据。


另一方面,Solid 使用了细粒度的响应性,和第 4 组中最慢的几个老库类似。这种技术又能占据榜首是挺奇怪的事情,但正如我们所见,Solid 解决了它们的缺陷。它的创建时间与更新时间一样快。与纯 JavaScript 只有 5%差距,这一事实令人难以置信。


奇怪的是,Inferno 和 Solid 的共同点是 JSX 模板和受 React 启发的 API。在其他那些有着定制优化 DSL 的库中,你大概不会看到这种东西和顶级性能同时出现。但正如 HyperApp 展示的一样,某些事情对性能的影响比人们想象的要小很多。


第 1 组启动成绩


继 HyperApp 和 Svelte 后,Solid 是第三个比纯 JS 实现更小的库,但 Inferno 也不落下风。


虽然高性能库一般会比较小,但有时添加更多代码可以提高性能,带来更好的列表一致性对比算法、更明确的防护措施、更精细的更新,等等。


Inferno 可能比前几组中的某些库更大,但它也还是一个不到 10kb 的库,而性能则超过几乎所有对手。


第 1 组内存成绩


如你所见,除了使用 WASM 的 Yew 以外,它们是整个对比中内存消耗最少的框架。考虑到它们的速度表现,这个结果并不奇怪。


这些内存消耗数字反映了设计者对对象和闭包创建有着非常深度的思考。两个库都做了定制的 JSX 转换,带来了很多收益。


内存性能的提升对 Solid 尤为重要,因为 Solid 与大多数细粒度的响应库一样,都将 CPU 开销换成了内存消耗。在这种对比中,Solid 之所以采用了和多数最慢的库类似的技术,却能提供最出色的成绩,很大一部分功劳都来自于它成功解决了内存消耗问题。

第 1 组结果


接近极限。


虽说纯 JavaScript 是上限,但我们这里的声明式库性能几乎没怎么落后,你完全感觉不到它们的差距。虽然我们都觉得 DOM 不行,但只要精心设计,有很多技术都可以高效渲染 DOM。


这里我们也看到了证据。Solid 在十年前就被认为是古老而缓慢的技术,可它竟然夺得了性能冠军,而 Inferno 再一次证明了虚拟 DOM 可以高效完成任何任务。

结论


在构建 JavaScript 前端时,我们有很多选择。本文只是帮助大家快速了解框架带来的性能开销。当涉及到应用程序中的实际性能主题时,用户代码的影响会更大。


但我想在这里真正强调的是,测试你的解决方案并了解性能表现是很重要的。现实和宣传总是会有差异。虚拟 DOM 不见得就那么慢。我们不能保证编译器一定会带来最小的包。定制模板 DSL 不见得最佳选项。


最后我把所有库放在一起做个对比。某个库排在后面,并不一定意味着它就很慢,但是与这些表现出色的竞争对手相比它的得分更差一些。

所有框架


所有框架放在同一张表上。

速度


启动


内存


最终排名


所有结果都加到一个列表中(第 1 名得 20 分,最后 1 名得 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 年写的这篇对比文章,这篇文章正是受其启发:


《JavaScript Frameworks, Performance Comparison》


原文链接:《JavaScript Frameworks, Performance Comparison 2020》

2021-01-29 11:4115515

评论 4 条评论

发布
用户头像
rust yew 的首页写着因为interface types还没有最后定案,所以速度比理想状态差好多。2022年底再看看
2022-02-23 13:39
回复
用户头像
那么,在哪里可以看到“Solid”的官网呢。
2021-02-18 10:23
回复
2021-05-09 01:13
回复
用户头像
你说的很好,我还是用jQuery吧
2021-02-07 09:16
回复
没有更多了
发现更多内容

React Native 跨端框架与小程序混编的方法

Geek_99967b

小程序

openharmony萌新贡献指南

坚果

开源 HarmonyOS OpenHarmony 7月月更

文档协同工具推荐

Baklib

IMPALA2.12环境安装

怀瑾握瑜的嘉与嘉

7月月更

如何搭建清晰易懂的数据看板?

字节跳动数据平台

字节跳动 BI BI 分析工具 sentinel dashboard 可视化看板

【刷题记录】15.三数之和

WangNing

7月月更

【Docker 那些事儿】容器监控系统,来自Docker的暴击

Albert Edison

Docker 云计算 Kubernetes 云原生 7月月更

深度遍历:统计最高分的节点数目 🐟

空城机

算法题 7月月更

连续最大和与判断回文

未见花闻

7月月更

基于 SPICE 协议的硬编推流整合方案在云游戏中的应用

字节跳动视频云技术团队

视频编解码 云游戏

👈🏻👈🏻👈🏻你来追我呀!Flutter 实现追逐动画

岛上码农

flutter ios 移动端开发 安卓开发 7月月更

架构实战营第7模块作业

Geek_53787a

如何将 NFT 元数据从 IPFS 转移到智能合约中

devpoint

智能合约 NFT Metaverse 7月月更

学生思维VS职场思维

KEY.L

我有 7种 实现web实时消息推送的方案,7种!

程序员小富

Java springboot websocket 消息系统

Paper Time 回顾|MB2:为自治数据库建立行为模型

OceanBase 数据库

你的技术leader不懂这个?没有它就是没有设计的完成思考过程

田晓亮

方法论 架构设计

Docker 搭建 MySQL 主从复制

宁在春

MySQL Docker 主从复制 7月月更

承上启下继往开来,Python3上下文管理器(ContextManagers)与With关键字的迷思

刘悦的技术博客

Python 数据库 Python3 上下文 上下文管理器

nacos注册中心之服务地址的查询

急需上岸的小谢

7月月更

王者荣耀商城异地多活架构设计

joak

典型的数据湖应用案例

五分钟学大数据

数据湖 7月月更

Seata 多语言体系建设

SOFAStack

开源项目 seata 开源软件 多编程语言 项目共建

DeFi 2.0的LaaS协议,重振DeFi赛道发展的关键

BlockChain先知

连接无限·协同无界|融云首届全球企业通信云大会 WECC 来了

融云 RongCloud

通信云

力扣第三题——无重复字符的最长子串

为自己带盐

力扣

物联网技术在物联网产业格局的分布与应用

AIRIOT

低代码 物联网 低代码,项目开发

论文领读|面向机器翻译的多语言预训练技术哪家强?最新进展一睹为快!

澜舟孟子开源社区

人工智能 自然语言处理 机器学习 后端 机器翻译

Baklib:分享一些关于建设企业知识管理(KM)的方法

Baklib

Linux并不是一个操作系统

冯亮

Linux GNU

JS框架性能对比:Solid 高居榜首,Vue、React 和 Angular 竟纷纷跌出前十_语言 & 开发_Ryan Carniato_InfoQ精选文章