1. diff算法
React組件的核心思想是:
- 將頁面拆分為一個個組件,一個組件還可能嵌套更小的組件,每個組件都有自己的數據,當某個組件的數據發生變化時,更新該組件的部分視圖。
- 更新的過程是由數據驅動的,新的數據自該組件頂層向下流向子組件,每個組件調用自己的render方法得到新的視圖,并與之前的視圖diff比較差異,完成更新,這個過程就是reconciliation-調和
虛擬DOM基本原理:
用純js對象來模擬DOM樹,每當更新時,根據組件的render方法計算出新的虛擬DOM樹,并與之前的虛擬DOM樹作比較,得到一個差異補丁,最后隱射到真正的DOM樹上完成視圖更新,以減少操作DOM的次數
diff算法:前端很少跨越層級移動DOM元素,只會對虛擬DOM中同一層級的元素進行比較,這樣算法復雜度就可以達到O(n)
diff碰到列表會有問題
發現列表元素不同時,就會對其進行重渲染,但是可能只是進行了插入操作,只需要進行移動操作即可,需要定義key屬性,diff時就會去查找是否有相同的key元素,比較它們是否完全相同,若是則會復用該元素,免去不必要的操作
不推薦使用數組的index作為key,因為如果數據重排,index并不能起到唯一標識的作用,每次視圖元素都會重新渲染
diff會幫我們計算出虛擬DOM中真正變化的部分,并只針對該部分進行原生DOM操作,而非重新渲染整個頁面,從而保證了每次操作更新后頁面的高效渲染
傳統diff算法循環遞歸對節點進行依次比較,算法復雜度為O(n3),React可以轉化為O(n)復雜度
2.diff策略
diff算法的三個策略
- DOM節點的跨層級的移動操作特別少,可以忽略不計
- 擁有相同類的兩個組件會生成相似的樹形結構,擁有不同類的兩個組件會生成不同的樹形結構
- 對于同一層級的一組子節點,它們可以通過唯一id進行區分
2.1 tree diff
對樹進行分層比較,兩棵樹只會對同一層次的節點進行比較,即同一個父節點下的所有子節點,當發現節點已經不存在時,則該節點及其子節點會被完全刪除掉,不會用于進一步的比較,這樣只需要對樹進行一次遍歷
當出現節點跨層級移動時,并不會出現想象中的移動操作,而是移除不存在的節點及其子節點,創建存在的節點
注意:在開發組件時,保持穩定的DOM結構會有助于性能的提升,可以通過CSS隱藏或顯示節點,而不是真正移除或添加DOM節點
2.2 component diff
組件間比較:
- 同一類型組件,按照原策略繼續比較虛擬DOM樹
- 將該組件判斷為dirty component,替換整個組件下的所有子節點
- 同一類型組件,可能虛擬DOM完全沒有變化,用戶通過shouldComponentUpdate來判斷組件是否需要進行diff算法
即不同組件則,直接替換掉組件下的所有子節點