之前一直認為react的Virtual DOM操作會比傳統的操作DOM要快,這其實是錯誤的,React 從來沒有說過 “React 比原生操作 DOM 快”。如果沒有 Virtual DOM,簡單來想就是直接重置 innerHTML,一次操作完成更新,真正的問題是在 “全部重新渲染” 的思維模式下,即使只有一行數據變了,它也需要重置整個 innerHTML,這時候顯然就有大量的浪費。
什么是DOM Diff算法
Web界面由DOM樹來構成,當其中某一部分發生變化時,其實就是對應的某個DOM節點發生了變化。在React中,構建UI界面的思路是由當前狀態決定界面。前后兩個狀態就對應兩套界面,然后由React來比較兩個界面的區別,這就需要對DOM樹進行Diff算法分析。
- 兩個相同組件產生類似的DOM結構,不同的組件產生不同的DOM結構;
- 對於同一層次的一組子節點,它們可以通過唯一的id進行區分。

React只會對相同顏色方框內的DOM節點進行比較,即同一個父節點下的所有子節點。當發現節點已經不存在,則該節點及其子節點會被完全刪除掉,不會用於進一步的比較。這樣只需要對樹進行一次遍歷,便能完成整個DOM樹的比較。
然而,在列表節點的操作,通常包括添加、刪除和排序。例如下圖,我們需要往B和C直接插入節點F,在jQuery中我們可能會直接使用$(B).after(F)來實現。而在React中,我們只會告訴React新的界面應該是A-B-F-C-D-E,由Diff算法完成更新界面

這也是在使用react列表循環時加入key的一個重要原因,如果給每個節點唯一的標識(key),那么React能夠找到正確的位置去插入新的節點,實現有目的的增加和刪除操作,如果不加,react都會報一個警告,不去處理這個警告也無大礙,但是對追求性能的react來說,這無疑是一個大問題,沒有key,那么上面的操作就是將c替換成F,將D變為C,一個一個的刪除后重建,這樣的性能損耗在大量列表結構中顯得尤為突出。
在比較性能的時候,要分清楚初始渲染、小量數據更新、大量數據更新這些不同的場合。Virtual DOM、臟檢查 MVVM、數據收集 MVVM 在不同場合各有不同的表現和不同的優化需求。Virtual DOM 為了提升小量數據更新時的性能,也需要針對性的優化,比如 shouldComponentUpdate 或是 immutable data。
- 初始渲染:Virtual DOM > 臟檢查 >= 依賴收集
- 小量數據更新:依賴收集 >> Virtual DOM + 優化(shouldComponentUpdate控制渲染 ) > 臟檢查(無法優化) > Virtual DOM 無優化
- 大量數據更新:臟檢查 + 優化 >= 依賴收集 + 優化 > Virtual DOM(無法/無需優化)>> MVVM 無優化
