react 虛擬DOM的diff演算法

2021-10-02 08:01:49 字數 2677 閱讀 7599

1、state 資料

2、jsx模板

3、生成虛擬dom(虛擬dom就是乙個js物件,用它來描述真實dom)

['div',,

['span',,

'hello world']]

通過這樣的乙個js物件,我們就可以表述上面的dom結構了

4、用虛擬dom的結構,生成真實的dom,來顯示

'abc'

>

hello world<

/span>

<

/div>

5、state發生變化

6、新的虛擬dom(極大的提公升了效能)

['div',,

['span',,

'bye bye']]

7、比較原始虛擬dom和新的虛擬dom的區別,找到區別是span中的內容(極大的提公升了效能)

8、直接操作dom

,改變span中的內容diff —> difference

找原始的虛擬dom和新的虛擬dom的差異,這也就是我們第七步

react的diff演算法大大的提公升了兩個虛擬dom的比對效能

如上圖,虛擬dom當資料發生改變的時候,虛擬dom才會去做新的比對。當props或者是state改變時,資料發生改變。其實props的改變是因為父元件的state發生了改變,歸根到底都是呼叫setstate的時候資料才發生變化,然後虛擬dom才重新的比對。

setstate是非同步的原因,實際上是為了提公升react底層的效能。假設連續呼叫三次setstate,變更三組資料,那麼就會進行三次虛擬dom的比對,然後更新三次頁面。假設三次呼叫setstate的時間間隔非常的小,這樣比較浪費效能。所以react,在你連續呼叫三次setstate時,合併成一次setstate,只做一次虛擬dom的比對,然後去更新一次dom。這樣的話,就可以省去額外的兩次dom比對帶來的效能上的耗費。也就是說,setstate可以把多次setstate結合成一次setstate,減少虛擬dom比對的次數。

具體的diff演算法

如圖,diff演算法有個很重要的概念,叫做同級比較。左側是乙個虛擬dom,當資料發生改變的時候,右側又會生成乙個新的虛擬dom,然後要做兩個虛擬dom做比對,找到差異之後,去更新真實的dom。在比對的時候是同層比對。

首先會比較最頂層的虛擬dom節點是否一致,假設一致,再去比較下乙個層。假設第一層的兩個虛擬dom不一致,這個時候怎麼辦呢?這個時候react就不會往下比了,他會把原始頁面上的虛擬dom下面的節點的dom全部刪除掉,重新生成一遍節點下面的所有dom,然後用重新生成的dom,替換原始頁面的dom,也就是只比對一層虛擬dom,大家可能會想,這不是效能很低嗎?假設第一層節點不同,下面的節點都相同,豈不是下面的節點都沒法復用了,確實是這樣的,雖然會造成一些dom節點的渲染浪費,但是這種比對有什麼好處呢?

我們說同層比對,帶來的演算法非常的簡單,只要一層一層的做對比就行了,演算法簡單,帶來的好處就是比對的速度會非常的快,所以可能會造成重新渲染的一些浪費,但大大減少了兩個虛擬dom之間比對的演算法上的效能消耗。所以採用了同層比對的演算法。也就是說diff演算法比對兩個虛擬dom差異的時候,逐層比對,一層不滿足匹配的要求,那麼下面的話就不會再去比對了,直接就廢棄掉,用下面的新的替換掉老的,這樣的話,會提公升效能。

再如圖,假設我有1個陣列,陣列裡面有5個資料,然後在頁面第一次渲染的時候,我會把這個5個資料對映成5個虛擬dom節點,生成乙個小的虛擬dom樹,接著我又往陣列裡面增加一些內容,於是資料發生變化,會生成乙個新的虛擬dom樹,然後會做兩個虛擬dom之間的比對,就是圖左上下進行比對,如果每個虛擬dom沒有乙個key值,就沒有乙個自己的名字,當作兩個虛擬dom樹比對的時候,節點和節點之間的關係就很難被確定,比如第二個虛擬dom上的節點,下面的第乙個是跟上面的第乙個比對,還是跟下面的第二個進行比對,這個很難做判斷。

所以需要做兩層迴圈的乙個比較,這樣比較起來就很麻煩了,也比較耗效能。現在加入在給虛擬dom迴圈的時候,我們可以給每乙個節點起乙個名字。如圖右,虛擬dom根據key值做關聯,只要找到對應的名字一樣的節點是否相同,極大的提高了react的效能。

前提:之前虛擬樹上的abcde,到了新的虛擬dom上,他的名字依然還叫作abcde,這就是迴圈中,key值為啥不叫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值,那麼使用乙個穩定的key值,才是正確的做法,在我們todolist案例中,可以將key值設為item內容。

React 虛擬 Dom 和 diff 演算法

react將dom抽象為虛擬dom,然後通過新舊虛擬dom 這兩個物件的差異 diff演算法 最終只把變化的部分重新渲染,提高渲染效率的過程 概念講完再描述一遍 一句話 用 js 物件的形式,來表現一棵真是的 dom 樹 傳統的 diff 演算法也是一直都有的 react 通過制定大膽的策略,將 o...

react 虛擬DOM及diff演算法

在vue,react這些框架中,都是通過監聽資料的變化而相應的去渲染我們的檢視.但是如果每次修改資料就去操作一次dom樹,這在效能上無疑是大打折扣的.虛擬dom的出現就是為了解決這個問題,並且起到協調的作用.本質上就是在js和真實dom樹之間做了乙個快取,具體原理是 每次當資料發生變化時,渲染機制先...

react虛擬DOM 中的 diff 演算法

定義 state,有了資料 有乙個模板 資料 模板生成虛擬 dom 虛擬 dom 就是乙個 js物件,用它來描述真實 dom 用虛擬 dom 的結構生成真實的 dom,來顯示 state 發生變化 資料 模板 生成新的虛擬 dom 極大地提公升效能 比較原始虛擬 dom和原始虛擬 dom的區別,找到...