react中虛擬dom的diff算法


1、state 數據
2、jsx模板
3、生成虛擬dom(虛擬DOM就是一個js對象,用它來描述真實DOM)
['div', {id:'abc'}, ['span', {}, 'hello world']]
通過這樣的一個js對象,我們就可以表述上面的dom結構了
4、用虛擬dom的結構,生成真實的dom,來顯示
<div id='abc'><span>hello world</span></div>
5、state發生變化
6、新的虛擬dom(極大的提升了性能)
['div', {id:'abc'}, ['span', {}, 'bye bye']]
7、比較原始虛擬DOM和新的虛擬DOM的區別,找到區別是span中的內容(極大的提升了性能)
8、直接操作DOM,改變span中的內容

 

現在看第7步,比較原始虛擬DOM和新的虛擬DOM的區別,這個時候兩個虛擬dom應該如何被比對,那么她們比對的方式就算作diff算法。

 

 

實際上react的diff算法大大的提升了兩個虛擬dom的比對性能,如圖,虛擬dom什么時候會被比對,當數據發生改變的時候,虛擬dom才會去做新的比對,那么什么時候數據發生了改變了呢,要么改變了props,要么改變了state。其實props的改變是因為父組件的state發生了改變,所以其實都是setState數據才發生變化。之前說過setState是異步的,那么為什么是異步呢,實際上是為了提升react底層的性能,假設連續調用三次setState,變更三組數據,那么就會進行三次虛擬dom的比對,然后更新三次頁面,假設三次改變,時間間隔非常的小,這樣會比較浪費性能,所以react,把三次比對變成一次比對,這樣就會優化比對帶來的性能問題,所以設置react為異步函數。接下來看具體的diff算法

 

如圖,diff算法有個很重要的概念,叫做同級比較,首先會比較最頂層的虛擬dom節點是否一致,假設一致,再去比較下一個節點。假設第一層虛擬dom不一致,這個時候怎么辦呢?這個時候react就不會往下比了,他會原始的虛擬dom下面的節點全部刪除掉,重新生成一遍節點下面的所有dom,然后用重新生成的dom,替換原始頁面的dom,也就是只比對一層dom,大家可能會想,這不是性能很低嗎?假設第一層節點不同,下面的節點都相同,豈不是下面的節點都沒法復用了,確實是這樣的,雖然會造成一些dom節點的渲染浪費,但是這種比對有什么好處呢?我們說同層比對,帶來的算法非常的簡單,只要一層一層的做對比就行了,算法簡單,帶來的好處就是比對的速度會非常的快,所以可能會造成重新渲染的一些浪費,但大大減少了去比對的算法上的性能消耗。所以采用了同層比對的算法。

再如圖,假設我有1個數組,數組里面有5個數據,然后在頁面第一次渲染的時候,我會把這個5個數據映射成5個虛擬dom節點,生成一個小的虛擬dom樹,接着我又往數組里面增加一些內容,於是數據發生變化,會生成一個新的虛擬dom樹,然后會進行一個比對,就是圖左上下進行比對,如果每個虛擬dom沒有一個key值,就沒有一個自己的名字,當作兩個虛擬dom樹比對的時候,節點和節點之間的關系就很難被確定,比如下面的第一個是跟上面的第一個是一個即誒單,還是跟第二個是一個節點,很難做判斷,所以得做兩層循環的一個比較,這樣比較起來就很麻煩了,也比較耗性能,現在加入在給虛擬dom循環的時候,我們可以給每一個節點起一個名字多好,如圖右,虛擬dom根據key值做關聯,只要找到對應的名字一樣的節點是否相同,極大的提高了react的性能。這里就是為什么不要用index,如果key值是index的話,就沒法保證在原始的虛擬dom樹上,他的key值和虛擬dom樹上的key值一致了。舉個例子,比如一個數組

a-0 b-1 c-2
這個時候把a刪除掉
b-0 c-1
這時候問題來了,原來b的key值是1,現在b的key值是0,所以以前的b,和現在的b就無法建立起關系,這個key值就不好用了,這就是用index作key值的一個問題,他會導致key值不穩定,這個時候失去了key值的意義,所以我們說不要用index作為key值,

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM