react diff演算法詳解

2021-09-13 15:35:48 字數 3673 閱讀 1548

react之所以可以快速更新dom,在於react可以對比虛擬dom,找到差異後,只更新改變的部分。

diff演算法有很多,比如dfs演算法o(n^3)  > cito.js> kivi.jso(n^2)

對於react,fb通過大膽的策略,滿足了大多數的效能最大化,將o(n3)複雜度的問題成功的轉換成了o(n),並且後面對於同級節點移動,犧牲一定的dom操作,演算法的複雜度也才打到o(max(m,n))。

react原始碼(0.3)實現:

updatemultichild: function(nextchildren, transaction)  else if (nextchildren && !this._renderedchildren) ; // lazily allocate backing store with nothing

} else if (!nextchildren && this._renderedchildren) ;

}var rootdomiddot = this._rootnodeid + '.';

var markupbuffer = null; // accumulate adjacent new children markup.

var numpendinginsert = 0; // how many root nodes are waiting in markupbuffer

var loopdomindex = 0; // index of loop through new children.

var curchildrendomindex = 0; // see (comment 1)

for (var name in nextchildren)

// 獲取當前節點與要渲染的節點

var curchild = this._renderedchildren[name];

var nextchild = nextchildren[name];

// 是否兩個節點都存在,且型別相同

if (shouldmanageexisting(curchild, nextchild))

numpendinginsert = 0;

// 如果找到當前要渲染的節點序號比最大序號小,則移動節點

/** 在0.3中,沒有根據key做diff,而是通過object中的key作為索引

* 比如替換成

* b._domindex = 1挪到loopdomindex = 1的位置,就是原地不動

a._domindex = 0挪到loopdomindex = 2的位置,也就是和c換位

*/ if (curchild._domindex < curchildrendomindex)

curchildrendomindex = math.max(curchild._domindex, curchildrendomindex);

// 遞迴更新子節點props,呼叫子節點dom-diff...

!nextchild.props.isstatic &&

curchild.receiveprops(nextchild.props, transaction);

curchild._domindex = loopdomindex;

} else

// 當前不存在,下個節點存在, 執行插入,渲染下個節點

if (nextchild)

}loopdomindex = nextchild ? loopdomindex + 1 : loopdomindex;

}// 執行插入操作,插入位置計算方式如下:

// 要渲染的節點位置-要插入的節點個數:比如當前要渲染的節點index=3,當前節點只有乙個,也就是index=1。

// 如1

渲染成123

// 那麼從2

開始就開始加入buffer,最終buffer內容為2

3 // 那麼要插入的位置為 3 - 1 = 2。我們以1

為1,就是把buffer插入2的位置,也就是1

後面 if (markupbuffer)

// 迴圈老節點

for (var childname in this._renderedchildren)

var child = this._renderedchildren[childname];

// 當前節點存在,下個節點不存在,刪除

if (child && !nextchildren[childname])

}// 一次提交所有操作

this.processchilddomoperationsqueue();

}

diff和dom更新關聯圖:

三個大膽策略詳解:

只會對同一層次的節點進行比較,如果節點不存在直接刪除建立

同一型別的元件繼續tree diff比較,不同型別的元件直接刪除重建。

三種方法:插入,移動,刪除

舉個例子:

state = 

componentdidmount = () => )},5000)

}//render兩種情況

//一種key = ) }

//一種key = ) }

上面例子中第一種情況,在testlist改變後:三個節點都會更新

第二種情況,會先刪除,再移動,再插入

為什麼會有上述兩種情況的區別呢?

對於第一種情況:

key = 在更新前後是相同的,都是1,2,3

但是對比,key相同時,元素不同,則刪除插入

對於第二種情況;

key =   key分別是 'll','ww','kk' ,更新後虛擬dom key分別是kk ll ww,在進行element diff時,發現kk元素節點在更新前後是相同的,無需建立,會進行移動

說明:對於第一種情況,其實和沒有key是一樣的,除非其順序和key保持一致;

針對這一現象,react 提出優化策略:允許開發者對同一層級的同組子節點,新增唯一 key 進行區分,雖然只是小小的改動,效能上卻發生了翻天覆地的變化!

第二種情況的key和順序無關,可以找到更新前後沒有更改的元素節點。

總結:參考:

React Diff 演算法及效能優化

setstate是非同步操作,多次setstate合併成一次setstate,減少 diff 比對 兩個虛擬 dom 進行比對時,從上往下進行比對,如果同一層比對存在差異時就不會繼續進行比對 引入 key 值提高比對效能,其中 key 值最好不要為 index,應該是固定 唯一的值,比如 item ...

A 演算法詳解

第一部分 a 演算法簡介 寫這篇文章的初衷是應乙個的要求,當然我也發現現在有關人工智慧的中文站點實在太少,我在這裡 拋磚引玉,希望大家都來熱心的參與。還是說正題,我先拿a 演算法開刀,是因為a 在遊戲中有它很典型的用法,是人工智慧在遊戲中的代表。a 演算法在人工智慧中是一種典型的啟發式搜尋演算法,為...

A 演算法詳解

a 演算法的基本原理 a star演算法是一種靜態路網中求解最短路徑最有效的直接搜尋方法,也是解決許多搜尋問題的有效演算法。演算法中的距離估算值與實際值越接近,最終搜尋速度越快。f i g i h i 以上式子中 g i 表示從起點到當前節點已經付出的代價,這個是準確的 a 演算法最重要的是估價函式...