React 虛擬DOM及diff算法

虛擬DOM合理性

由於操作DOM很慢,界面性能很多都是操作DOM引起的,而操作JS很快,用JavaScript對象很容易表示DOM節點,包括標籤屬性子節點,即根據DOM結構遞歸創建虛擬DOM樹,在頁面狀態改變需要操作DOM時,先通過虛擬DOM計算出對真實DOM的最小修改量,然後再修改真實的DOM。

  • 1.兩個相同組件產生類似的結構,不同組件產生不同的DOM結構。
  • 2.對於同一層次的一組子節點,通過唯一的key值進行區分。

一、不同節點類型的比較

  • 在虛擬樹中比較兩個虛擬DOM節點,若兩個節點類型不同,則直接銷燬前面的節點,創建並插入新節點。
  • 若被刪除的節點之下還有子節點,那麼這些子節點也會一併刪除。因爲一般情況不同組件產生不同的DOM結構,與其浪費時間比較他們基本不會相等的DOM結構還不如加個新組建上去。

二、只會逐層比較節點

比如A節點下有子節點BC,要將A節點包括其子節點移動到其他節點下面,則不是將A賦值並移動到其他節點如D下面,而是重新創建每一個節點:

A.destroy();
A = new A();
a.append(new B());
a.append(new C());
D.append(A);

三、相同節點類型的比較

相同類型的節點, 對屬性進行重設。

四、列表節點的比較

列表中節點若沒有唯一標識的key值的話,會提示警告。
假設在列表ABCD中B的後面插入E,若沒有key值則會將C更新爲E,將D更新爲C,最後插入D節點。
但是若有key值的話,react會找到正確的插入位置。
還有若A下面有BC子節點,若未提供key值,則react認爲BC類型不同,要調整BC的位置會將BC刪除後重新新建再插入,若有key值的話,則只是更新BC和其父組件而已。

diff算法

diff算法採用動態規劃的方法求兩個序列X和Y,長度分別爲m,n,的最長公共子序列,時間複雜度爲mn,比較兩顆樹的時間複雜度爲n^3,因爲樹遍歷複雜度爲n
假設有兩個序列X=(GAC),長度爲m,Y=(AGCAT),長度爲n,則X和Y的嘴饞公共子序列爲:

這裏寫圖片描述

最長公共子序列LCS(Xi,Yj)分析:

  • X或者Y中有一個長度爲0時,其公共子序列爲空;
  • XY的第i個字符相等時,其公共子序列LCS(Xi,Yj)=XiLCS(Xi-1,Yj-1);
  • XY的第i個字符不相等時,其公共子序列LCS(Xi,Yj)LCS(Xi,Yj-1)LCS(Xi-1,Yj)中最大的一個。

這裏寫圖片描述

由於第i次構造最長公共子序列時要用到第i-1次的最長公共子序列,因此將第一次構造時的最長公共子序列設爲空;
舉例:

  • 最後一個格子,CT不等,因此,取LCS('GAC','AGCA')=倒數第一行倒數第二個格子LCS('GA','AGCAT')=倒數第一列倒數第二個格子的最大值,即(AC)&(GC)&(GA);

  • 第4行的A和第6列的A相等時取ALCS('G','AGC')=G.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章