React 虛擬 Dom 和 diff 演算法

weixin_33809981發表於2017-12-14

React將DOM抽象為虛擬DOM, 然後通過新舊虛擬DOM 這兩個物件的差異(Diff演算法),最終只把變化的部分重新渲染,提高渲染效率的過程; (概念講完再描述一遍)

一句話: 用 JS 物件的形式,來表現一棵真是的 DOM 樹;


Diff 演算法

    • 當你實際開發使用React的時候,在某個時間點 render() 函式建立了一棵React元素樹,也就模擬一個虛擬 DOM 樹,
    • 在下一個state或者props更新的時候,render() 函式將建立一棵新的React元素樹, 也就模擬了一個新的虛擬 DOM 樹,
    • 既然模擬出了新舊兩棵DOM 樹, 那麼如何高效的進行新舊兩棵樹的對比呢??
    • 當然是使用 DIff 演算法...
  1. 傳統的 Diff 演算法也是一直都有的;

    • 但是它的時間複雜度為O(n^3) 意思是: 在React中更新10個元素則需要進行1000次的比較。(1000個===10億)
  2. React 通過制定大膽的策略,將 O(n^3) 複雜度的問題轉換成 O(n^1=n) 複雜度的問題。

      1. 兩個不同型別的元素會產生不同的樹
      1. 對於同一層級的一組子節點,它們可以通過唯一 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 演算法總結:

  1. 保持完整的結構,有利於效能的提升

  2. 儘量使用相同型別的元件

  3. 在進行 Element 或Component 級別對比的時候,為了提高對比的效率, React 推薦我們為每個 for 迴圈建立出來的元素或者元件,提供一個唯一的 key;

  4. Tree diff :將新舊兩棵 DOM 樹,按照層級對應的關係,這樣只需要對樹進行一次遍歷,就能夠找到哪些元素是需要更新的;

  5. Component Diff: 在對比每一層的時候,每一層都有自己的元件, 那麼元件之間的對比,叫做 Component diff , 對比的方式,就是檢視兩個元件的型別是否相同,如果相同,則暫時認為不需要更新,如果型別不同,則表示更新(先把舊的元件刪除,再建立一個新的元件,插入到剛才刪除的位置);

  6. Element Diff:如果新舊 DOM 樹中的元件型別相同,會繼續比較這兩個元件內部的元素是否也相同,如果元素髮生了改變,則找到需要修改的元素,有針對性的修改,這種元件內部元素級別的對比叫: Element Diff;

相關文章