跳轉到

淺談前端框架

原生 DOM 操作 vs. 通過框架封裝操作

這是一個性能跟可維護性的取捨。框架的意義在於為你掩蓋底層的 DOM 操作,讓你用更聲明式的方式 (Declarative Programming) 來描述你的目的,從而讓你的代碼更容易維護。沒有任何框架可以比純手動的優化 DOM 操作更快,因為框架的 DOM 操作層需要應對任何上層 API 可能產生的操作,它的實現必須是普適的。針對任何一個 benchmark,我都可以寫出比任何框架更快的手動優化,但那有什麼意義呢?在構建一個實際應用的時候,你難道會為每一個地方都去做手動優化嗎?出於可維護性的考慮,這顯然不可能。框架給你的保證是,你在不需要手動優化的情況下,我依然可以給你提供過得去的性能

對 React 的 Virtual DOM 的誤解

React 從來沒有說過 “React 比原生操作 DOM 快”。React 的基本思維模式是每次有變動就整個重新渲染整個應用。如果沒有 Virtual DOM,簡單來想就是直接重置 innerHTML。很多人都沒有意識到,在一個大型列表所有數據都變了的情況下,重置 innerHTML 其實是一個還算合理的操作,真正的問題是在“全部重新渲染” 的思維模式下,即使只有一行數據變了,它也需要重置整個 innerHTML,這時候顯然就有大量的浪費。

Virtual DOM render + diff 顯然比渲染 html 字符串要慢,但是!它依然是純 js 層面的計算,比起後面的 DOM 操作來說,依然便宜了太多。可以看到,innerHTML 的總計算量不管是 js 計算還是 DOM 操作都是和整個界面的大小相關,但 Virtual DOM 的計算量裡面,只有 js 計算和界面大小相關,DOM 操作是和數據的變動量相關的。前面說了,和 DOM 操作比起來,js 計算是極其便宜的。這才是為什麼要有 Virtual DOM:它保證了

  1. 不管你的數據變化多少,每次重繪的性能都可以接受
  2. 你依然可以用類似 innerHTML 的思路去寫你的應用。

MVVM vs. Virtual DOM

MVVM 的變化檢查是數據層面的,而 React 的檢查是 DOM 結構層面的。MVVM 渲染列表的時候,由於每一行都有自己的數據作用域,所以通常都是每一行有一個對應的 ViewModel 實例,或者是一個稍微輕量一些的利用原型繼承的"scope" 對象,但也有一定的代價。所以,MVVM 列表渲染的初始化幾乎一定比 React 慢,因為創建 ViewModel / scope 實例比起 Virtual DOM 來說要昂貴很多。這裡所有 MVVM 實現的一個共同問題就是在列表渲染的數據源變動時,尤其是當數據是全新的對象時,如何有效地複用已經創建的 ViewModel 實例和 DOM 元素。假如沒有任何復用方面的優化,由於數據是“全新” 的,MVVM 實際上需要銷毀之前的所有實例,重新創建所有實例,最後再進行一次渲染!相比之下,React 的變動檢查由於是 DOM 結構層面的,即使是全新的數據,只要最後渲染結果沒變,那麼就不需要做無用功。

性能比較也要看場合

在比較性能的時候,要分清楚初始渲染、小量數據更新、大量數據更新這些不同的場合。

  • 初始渲染: Virtual DOM > 依賴收集
  • 小量數據更新: 依賴收集 >> Virtual DOM + 優化(memo、shouldComponentUpdate) > Virtual DOM 無優化
  • 大量數據更新: 依賴收集 + 優化 > Virtual DOM(無法/無需優化) >> 依賴收集(無優化)

Reference