計算兩顆樹形結構差別並進行轉換vue
文中, 所說起n均表明節點的個數node
處理方案: 循環遞歸每個節點react
傳統diffweb
如上所示, 左側樹a節點依次進行以下對比:算法
a->e、a->d、a->b、a->c、a->adom
以後左側樹其它節點b、c、d、e亦是與右側樹每一個節點對比, 算法複雜度能達到O(n^2)函數
查找完差別後還需計算最小轉換方式,這其中的原理我沒仔細去看,最終達到的算法複雜度是O(n^3)性能
將兩顆樹中全部的節點一一對比須要O(n²)的複雜度,在對比過程當中發現舊節點在新的樹中未找到,那麼就須要把舊節點刪除,刪除一棵樹的一個節點(找到一個合適的節點放到被刪除的位置)的時間複雜度爲O(n),同理添加新節點的複雜度也是O(n),合起來diff兩個樹的複雜度就是O(n³)優化
vue和react的虛擬DOM的diff算法大體相同,其核心是基於兩個簡單的假設:component
(優化的)diff三點策略:
即, 比較只會在同層級進行, 不會跨層級比較
基於以上優化的diff三點策略,react分別進行如下算法優化
react對樹的算法進行了分層比較。react 經過 updateDepth對Virtual Dom樹進行層級控制,只會對相同顏色框內的節點進行比較,即同一個父節點下的全部子節點。當發現節點不存在,則該節點和其子節點都會被刪除。這樣是須要遍歷一次dom樹,就完成了整個dom樹的對比
分層比較 img
若是是跨層級的移動操做,如圖
跨層級操做 img
當根結點發現A消失了,會刪除掉A以及他的子節點。當發現D上多了一個A節點,會建立A(包括其子節點)節點做爲子節點
因此:當進行跨層級的移動操做,react並非簡單的進行移動,而是進行了刪除和建立的操做,這會影響到react性能。因此要儘可能避免跨層級的操做。(例如:控制display來達到顯示和隱藏,而不是真的添加和刪除dom)
component vs img
若是組件D和組件G,若是類型不一樣,可是結構相似。這種狀況下,由於類型不一樣,因此react會刪除D,建立G。因此咱們可使用shouldComponentUpdate()返回false不進行diff。
針對react15, 16出了新的生命週期
因此:component diff 主要是使用shouldComponentUpdate() 來進行優化
element diff 涉及三種操做:插入,移動,刪除
不使用key的狀況 img
不使用key的話,react對新老集合對比,發現新集合中B不等於老集合中的A,因而刪除了A,建立了B,依此類推直到刪除了老集合中的D,建立了C於新集合。=
醬紫會產生渲染性能瓶頸,因而react容許添加key進行區分
使用key的狀況 img
react首先對新集合進行遍歷,for( name in nextChildren),經過惟一key來判斷老集合中是否存在相同的節點,若是沒有的話建立,若是有的話,if (preChild === nextChild ) 進行移動操做
移動優化
在移動前,會將節點在新集合中的位置和在老集合中lastIndex進行比較,若是if (child._mountIndex < lastIndex) 進行移動操做,不然不進行移動操做。這是一種順序移動優化。只有在新集合的位置 小於 在老集合中的位置 才進行移動。
若是遍歷的過程當中,發如今新集合中沒有,可是在老集合中的節點,會進行刪除操做
因此:element diff 經過惟一key 進行diff 優化。
總結:
1.react中儘可能減小跨層級的操做。 2.可使用shouldComponentUpdate() 來避免react重複渲染。 3.添加惟一key,減小沒必要要的重渲染
vue2.0加入了virtual dom,和react擁有相同的 diff 優化原則
差別就在於, diff的過程就是調用patch函數,就像打補丁同樣修改真實dom
updateChildren是vue diff的核心
過程能夠歸納爲:oldCh和newCh各有兩個頭尾的變量StartIdx和EndIdx,它們的2個變量相互比較,一共有4種比較方式。若是4種比較都沒匹配,若是設置了key,就會用key進行比較,在比較的過程當中,變量會往中間靠,一旦StartIdx>EndIdx代表oldCh和newCh至少有一個已經遍歷完了,就會結束比較