React將DOM抽象為虛擬DOM, 然後通過新舊虛擬DOM 這兩個物件的差異(Diff演算法),最終只把變化的部分重新渲染,提高渲染效率的過程; (概念講完再描述一遍)
一句話: 用 JS 物件的形式,來表現一棵真是的 DOM 樹;
Diff 演算法
-
- 當你實際開發使用React的時候,在某個時間點 render() 函式建立了一棵React元素樹,也就模擬一個虛擬 DOM 樹,
- 在下一個state或者props更新的時候,render() 函式將建立一棵新的React元素樹, 也就模擬了一個新的虛擬 DOM 樹,
- 既然模擬出了新舊兩棵DOM 樹, 那麼如何高效的進行新舊兩棵樹的對比呢??
- 當然是使用 DIff 演算法...
-
傳統的 Diff 演算法也是一直都有的;
- 但是它的時間複雜度為O(n^3) 意思是: 在React中更新10個元素則需要進行1000次的比較。(1000個===10億)
-
React 通過制定大膽的策略,將 O(n^3) 複雜度的問題轉換成 O(n^1=n) 複雜度的問題。
-
- 兩個不同型別的元素會產生不同的樹 和
-
- 對於同一層級的一組子節點,它們可以通過唯一 key 進行區分
- 基於以上兩個前提策略,React 分別對 tree diff、component diff 以及 element diff 三種 diff 方法是 進行演算法優化,
- 下面介紹優化後的幾種演算法
-
Tree Diff
概念: 將新舊兩顆虛擬 DOM 樹,按照層級對應的關係,從頭到尾的遍歷一遍,,就能找到那些元素是需要更新的,這種方式: Tree Diff
1 只會對相同顏色方框內(同級)的DOM節點進行比較,即同一父節點下的所有子節點
2 當發現節點已經不存在,則該節點及其子節點會被完全刪除掉,不會用於進一步的比較
複製程式碼
- 執行過程:create A -> create B -> create C -> delete A
Component Diff
不同元件之間的對比 概念: 在對比每一個層級的時候,會有自己的元件,這種元件的對比方式就叫: Component Diff ;
這種對比方法其實比較的就是型別.↓↓↓
-
如果型別相同,暫時不更新,
-
如果型別不相同,就需要更新; ( 刪除舊的元件,再建立一個新的元件,插入到刪除元件的那個位置)
- 執行過程:delete D -> create G
Element Diff
同一層級中元素之間的對比
概念: 在型別相同的元件內, 再繼續對比元件內部的元素,檢視內部元素是否相同,如果需要修改,找到需要修改的元素,進行鍼對性的修改! 這種方式就叫: Element Diff
三種節點操作:
1 INSERT_MARKUP(插入)
2 MOVE_EXISTING(移動)
3 REMOVE_NODE(刪除)
INSERT_MARKUP:新的 component 型別不在老集合裡,需要對新節點執行插入操作。
MOVE_EXISTING:老的集合包含新的 component 型別,就需要做移動操作,可以複用以前的 DOM 節點。
REMOVE_NODE:老的 component 不在新集合裡的,需要執行刪除操作 或者 老的 component 型別在新集合裡也有,但對應的 element 不同則不能直接複用和更新,需要執行刪除操作
複製程式碼
-
執行過程:B != A,則建立並插入 B,刪除 A;以此類推,建立並插入 A、D、C,刪除 B、C、D
-
執行過程:B、D 不做任何操作,A、C 進行移動操作
diff 演算法總結:
-
保持完整的結構,有利於效能的提升
-
儘量使用相同型別的元件
-
在進行 Element 或Component 級別對比的時候,為了提高對比的效率, React 推薦我們為每個 for 迴圈建立出來的元素或者元件,提供一個唯一的 key;
-
Tree diff :將新舊兩棵 DOM 樹,按照層級對應的關係,這樣只需要對樹進行一次遍歷,就能夠找到哪些元素是需要更新的;
-
Component Diff: 在對比每一層的時候,每一層都有自己的元件, 那麼元件之間的對比,叫做 Component diff , 對比的方式,就是檢視兩個元件的型別是否相同,如果相同,則暫時認為不需要更新,如果型別不同,則表示更新(先把舊的元件刪除,再建立一個新的元件,插入到剛才刪除的位置);
-
Element Diff:如果新舊 DOM 樹中的元件型別相同,會繼續比較這兩個元件內部的元素是否也相同,如果元素髮生了改變,則找到需要修改的元素,有針對性的修改,這種元件內部元素級別的對比叫: Element Diff;