大家好,我卡頌。
昨天在網上愉快衝浪時,看到一篇框架測評,效果屬實爆炸。
作者用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.
為啥差這麼多
簡單介紹下這個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
地址:
Demo
中獲取資料的API
的域名是rickandmortyapi.com
,居然還有這種網站......
歡迎加入人類高質量前端框架研究群,帶飛