React學習-- React原始碼(5)diff演算法
diff作為VirtualDOM的加速器,其演算法上的改進優化是React整個介面渲染的基礎和效能的保障。
diff會幫助我們就散出VirtualDOM中真正變化的部分,並只針對該部分進行原生DOM操作,而不是渲染整個頁面。從而保證了每次操作更新後頁面的高效渲染。
傳統的diff演算法
計算一顆樹形結構轉換成另一顆樹形結構的最少操作,是一個很複雜的問題。傳統diff演算法通過迴圈遞迴對節點進行依次對比,效率低下。複雜度可達到O(n^3)。
React改進了diff演算法,新的diff演算法更加穩定、高效。
React diff演算法詳解
React將VirtualDOM樹轉換為actualDOM的最少操作過程稱為調和(reconciliation)。
diff演算法就是調和過程的具體實現。
1、diff策略
策略1: DOM節點跨層級的移動操作很少,忽略不計。
策略2: 擁有相同類的兩個元件將會生成相似的樹形結構,擁有不同類的兩個元件將會生成不同的樹形結構。
策略3: 對於同一個層級的一組子節點,可以通過它們唯一的ID來區分。
2、tree diff
基於策略1,React對樹的演算法進行了簡潔明瞭的優化:只對樹進行分層比較,兩棵樹只會對同一層次的節點進行比較。
React只會對相同層級的DOM節點進行比較,即同一個父節點下的所有子節點,當發現該節點已經不存在了,就會刪除該節點和其所有子節點,不會再做進一步的比較。
而如果真的出現了跨層級的移動,並不會出現移動操作,而是被移動的跟節點被刪除而後重新建立。
3、component diff
元件之間的比較策略:
1、如果是同一型別的元件,按原策略繼續比較VirtualDOM樹即可
2、如果不是,則將該元件判斷為dirty component,從而替換整個元件下的所有子節點。
3、對於同一型別的元件,可能其virtualDOM沒有任何變化,如果能確切的知道這一點,那麼就可以節省大量的diff運算時間。因此,React允許使用者通過shouldComponentUpdate()來判斷是否需要對元件進行diff演算法分析。
4、element diff
當節點處於同一個層級的時候,diff提供了三種節點操作:INSERT_MARKUP(插入)、MOVE_EXISTING(移動)、REMOVE_NODE(刪除)。
1、插入:新的元件不在舊的集合裡,也就是是一個全新的節點。
2、舊集合中有新的元件型別,且element是可更新的型別,generateComponent-Children已經呼叫receiveComponent,這種情況下prevChild=nextChild,就需要做移動操作,可以複用以前的DOM節點。
3、舊元件型別,在新集合裡也有,但對應的element不同則不能直接複用和更新,需要執行刪除操作。或者舊元件不在新集合裡,也要執行刪除操作。