这波React属实被针对了
昨天在网上愉快冲浪时,看到一篇框架测评,效果属实爆炸。
作者用React
和Solid.js
开发了同样的Demo
。为什么用Solid.js
和React
对比呢,让我们看看Solid.js
的API
:
Hooks
Context、Portal API
Error Boundaries
不能说和React
多雷同,只能说一摸一样吧。而且Solid.js
也用JSX
描述视图,所以一个React
应用要改为Solid.js
应用的成本很小。
具体测评结果怎么样呢,差了快3倍,这一波React
属实被针对了。
本文参考SolidJS vs React: I've Built the Same App On Both Libraries.[1]
为啥差这么多
简单介绍下这个Demo
,初始渲染空白列表:
首次mount
完成后发起请求,渲染列表数据:
这是两个应用Chrome Dev Tools Performance
面板的结果:
解释下其中几个关键指标:
Loading:发起网络请求、解析HTML的时间
Scripting:解析、编译、执行
JS
的时间(包括垃圾回收时间)Rendering:
style
和layout
计算Painting:
paint
、composite
、解码图片
具体关注Scripting
,左475ms(React
),右176ms(Solid.js
)
2倍多的差距,这么夸张?
问题出在哪
前端框架的工作流程可以简单用三个步骤总结:
触发交互
计算交互会影响哪些
DOM
执行
DOM
操作
这里的交互可能是首屏渲染,可能是点击造成的状态变化、可能是请求数据......
在React
中,步骤2是在运行时完成的,而在Solid.js
中是在编译时完成的。
具体来说,该步骤在React
中被称为reconcile
,更普遍的称呼是虚拟DOM
的diff
算法。
在Performance
面板下面的Call Tree
中可以看到,执行XHR Load
(请求列表数据)前有个很耗时的操作(Function Call
),该操作即reconcile
。
而在Solid.js
应用中就没有这个耗时的操作:
在编译时,Solid.js
会将JSX
直接编译为状态
与操作DOM的方法
之间的联系。
由于JSX
太过灵活,为了在编译时有更多线索建立这种联系,Solid.js
在React
原有JSX
组件基础上提供了一些控制流组件
:
举个例子,下面是遍历列表项
在两个框架中的实现区别:
// React
<ul>
{list.map(
item => <li>{item.name}li>
)}
ul>
<ul>
// Solid.js
<ul>
<For each={list}>
{(item) => <li>{item.name}li>}
For>
ul>
For
组件替代了JS
中的数组map
方法。
当Solid.js
在编译时完成这些工作,在运行时每次更新实际只用完成步骤1和3,省去了大部分步骤2的时间。
虽然React
对reconcile
有优化策略,但随着应用体积增大,或者项目成员不完全遵守最佳实践,势必会造成在步骤2上花费的时间越来越多。
Solid.js
提前建立状态
与操作DOM的方法
之间的联系,虽然需要在运行时占用更多内存保存这种对应关系,但是却省去了大部分步骤2的时间,是一种典型的空间换时间的策略。
总结
说了这么多,虽然看起来Solid.js
对比React
在框架的某些方面是有优势的,但并不能撼动React
的统治地位。
毕竟,React
这么流行和他快不快一点关系都没有,社区生态繁荣才是最重要的。
还有个有意思的事,这里是文中的2个Demo
地址:
Solid.js版[2]
React版[3]
Demo
中获取数据的API
的域名是rickandmortyapi.com
,居然还有这种网站......
参考资料
SolidJS vs React: I've Built the Same App On Both Libraries.: https://dev.to/ogzhanolguncu/solidjs-vs-react-i-ve-built-the-same-app-on-both-libraries-4cfa
[2]Solid.js版: https://github.com/ogzhanolguncu/rick-and-morty-solidjs
[3]React版: https://github.com/ogzhanolguncu/react-rick