這波React屬實被針對了

卡頌發表於2021-10-21

大家好,我卡頌。

昨天在網上愉快衝浪時,看到一篇框架測評,效果屬實爆炸。

作者用ReactSolid.js開發了同樣的Demo。為什麼用Solid.jsReact對比呢,讓我們看看Solid.jsAPI

  • 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完成後發起請求,渲染列表資料:

Rick和Morty真愛粉無疑了

這是兩個應用Chrome Dev Tools Performance皮膚的結果:

左React 右Solid.js

解釋下其中幾個關鍵指標:

  • Loading:發起網路請求、解析HTML的時間
  • Scripting:解析、編譯、執行JS的時間(包括垃圾回收時間)
  • Rendering: stylelayout計算
  • Painting:paintcomposite、解碼圖片

具體關注Scripting,左475ms(React),右176ms(Solid.js

2倍多的差距,這麼誇張?

問題出在哪

前端框架的工作流程可以簡單用三個步驟總結:

  1. 觸發互動
  2. 計算互動會影響哪些DOM
  3. 執行DOM操作

這裡的互動可能是首屏渲染,可能是點選造成的狀態變化、可能是請求資料......

React中,步驟2是在執行時完成的,而在Solid.js中是在編譯時完成的。

具體來說,該步驟在React中被稱為reconcile,更普遍的稱呼是虛擬DOMdiff演算法。

Performance皮膚下面的Call Tree中可以看到,執行XHR Load(請求列表資料)前有個很耗時的操作(Function Call),該操作即reconcile

而在Solid.js應用中就沒有這個耗時的操作:

在編譯時,Solid.js會將JSX直接編譯為狀態操作DOM的方法之間的聯絡。

由於JSX太過靈活,為了在編譯時有更多線索建立這種聯絡,Solid.jsReact原有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的時間。

雖然Reactreconcile有優化策略,但隨著應用體積增大,或者專案成員不完全遵守最佳實踐,勢必會造成在步驟2上花費的時間越來越多。

Solid.js提前建立狀態操作DOM的方法之間的聯絡,雖然需要在執行時佔用更多記憶體儲存這種對應關係,但是卻省去了大部分步驟2的時間,是一種典型的空間換時間的策略。

總結

說了這麼多,雖然看起來Solid.js對比React在框架的某些方面是有優勢的,但並不能撼動React的統治地位。

畢竟,React這麼流行和他快不快一點關係都沒有,社群生態繁榮才是最重要的。

還有個有意思的事,這裡是文中的2個Demo地址:

Demo中獲取資料的API的域名是rickandmortyapi.com,居然還有這種網站......

歡迎加入人類高質量前端框架研究群,帶飛

相關文章