淺談React虛擬DOM Diff演算法
為什麼要使用虛擬DOM
因為瀏覽器的DOM渲染是非常消耗效能的,很低效,我們使用虛擬DOM是為了提高DOM的渲染效能;
什麼是虛擬DOM
虛擬DOM就是把真實的DOM樹通過createElement轉換成js中的一個物件樹,在內
存中作比較
在虛擬DOM中是如何渲染頁面的
虛擬DOM一旦建立以後,就會根據元件內部的狀態,父元件props傳過來的修改,以及一些全域性狀態的更新,就會導致當前
元件產生一個新的js物件樹,然後就會在記憶體中通過一個diff比較演算法來比較當前的虛擬DOM節點和之前的虛擬DOM節點,將比較
的結果在DOM樹上重新渲染
Diff演算法(逐層比較)
Diff演算法也叫同級比較演算法,是逐層比較的,一旦發現某個節點沒了,就刪除,發現新增了一個節點,那就新增一個節點,發現
該位置該存在,就原地保留該節點。但是標準的Diff演算法複雜度需要O的三次方,這樣的演算法顯示是無法滿足效能要求的,所以
勢必要對該演算法進行簡化的。這看上去非常有難度,然而Facebook工程師卻做到了,他們結合Web介面的特點做出了兩個簡單的
假設,使得Diff演算法複雜度直接降低到O(n)複雜度從O的三次方變為了O的一次方;同時也解決了兩個問題:如果兩棵樹比較變化
特別大,就完蛋了,如果兄弟節點進行排序和插入新節點,那還是完蛋,你要全刪了再一個一個加;
接下來就要說這兩個假設
(1)兩個相同元件產生類似的DOM結構,不同的元件產生不同的DOM結構;
(2)對於同一層次的一組子節點,它們可以通過唯一的id進行區分。
關於第一個假設
-其實看起來並不奇怪,在我們的react中,由於元件化的思想,相同元件中本就是類似的DOM解構,只有不同的元件才會產生不
同的DOM結構,根據React官方部落格,這一假設至今為止沒有導致嚴重的效能問題。
-這當然也給我們一個提示,在實現自己的元件時,保持穩定的DOM結構會有助於效能的提升。例如,我們有時候可以通過CSS隱
藏或顯示某些節點,而不是真正的去移除或新增DOM節點;
關於第二個假設,也就是我們為什麼迴圈的時候會加上一個key值的解釋
-你想,我們兄弟節點如果進行排序的時候,每個位置的節點都變了,那我們就要把每個位置的節點都重新刪除掉,然後再一個
一個的重新新增上去,這樣的話更新過程會特別的低效,所以第二個假設的作用就是讓我們開發者在開發過程中給每個節點加上
一個:key值,也就是給每個節點加上一個唯一標識,這樣就會根據列表節點提供唯一的key屬性可以幫助React定位到正確的節點
進行比較,從而大幅減少DOM操作次數,提高了效能。
還有一個就是我們給節點加標識的時候,儘量不要使用下標index
-如果你用下標,你要插入一個節點,那下標不就全亂了,但是我們也可以:key="“index”",將下標轉換成字串就行,但是我
們不提倡使用index作為key的,因為我們會用用資料庫返回來的id作為key值。