React中的虛擬DOM

當組件當state和props發生變化當時候,組件當render函數就會從新執行,組件就會被從新渲染,react中實現這種從新渲染,他的性能是很是高的,由於他引入了一個虛擬Dom的概念,那麼什麼是虛擬的Dom,爲何虛擬Dom帶來了變革性當改變

 

當state發生變化,render函數會從新執行,從新的去渲染一次頁面。假設沒有react,咱們本身要實現這個功能,那應該怎麼去實現呢?咱們來理個思路
1、state 數據
2、jsx模板
3、把數據 + 模板相結合,生成真實的dom,來顯示
4、state 發生改變
5、數據 + 模板 結合,生成真實的dom,替換原始的dom
這麼作,有一個致命的缺陷,是什麼呢?
第一次生成了一個完整的dom片斷
第二次生成了一個完整的dom片斷
第二次的dom替換第一次的dom,很是耗性能。當咱們inputvalue發生變化的時候,其實頁面上只有input這塊dom發生變化,若是是這種作法,雖然是input的數據發生變化,可是我須要整個dom區塊從新生成一次,替換掉原始的dom狀況,這樣的話,生成一個完整的dom片斷很耗性能,替換掉一個完整的dom片斷,也很耗性能。那咱們改良一下

 

1、state 數據
2、jsx模板
3、把數據 + 模板相結合,生成真實的dom,來顯示
4、state 發生改變
5、數據 + 模板 結合,生成真實的dom,並不直接替換原始的dom
6、新的dom(DocumentFragment) 和 原始的dom作比對,找差別
7、找出input框發生了變化
8、只用新的dom中的input元素,替換掉老的dom中的input元素
這樣的話,是有必定的性能提高的。當新的dom替換掉老的dom的時候,涉及到dom替換的操做或者dom比對的操做,其實是比較耗性能的,因此替換原始的dom耗費了大量的性能。新的作法是什麼呢,不替換老的dom,是拿新的dom和原始的dom作對比,只須要更改那一塊局部的元素,這樣dom替換內容變少了,因此這塊性能得以提高,雖然提高了dom替換的性能,可是他又損耗了一部分性能,損耗的性能是哪裏呢,損耗的是新的dom要和原有的dom作比對,這樣節約了一些性能,又消耗了一些性能,其實在性能的提高上,並非特別明顯。因而react提出了虛擬dom的方案



1、state 數據
2、jsx模板
3、把數據 + 模板相結合,生成真實的dom,來顯示
  <div id='abc'><span>hello world</span></div>
4、生成虛擬dom(虛擬DOM就是一個js對象,用它來描述真實DOM)
  ['div', {id:'abc'}, ['span', {}, 'hello world']]
  經過這樣的一個js對象,咱們就能夠表述上面的dom結構了
5、state發生變化
6、數據+模板生成新的虛擬dom(極大的提高了性能)
  ['div', {id:'abc'}, ['span', {}, 'bye bye']]
7、比較原始虛擬DOM和新的虛擬DOM的區別,找到區別是span中的內容(極大的提高了性能) 8、直接操做DOM,改變span中的內容
這種方案相對於上面的方案有什麼樣的好處,第4步看上去要去另外生成一個虛擬dom,好像還消耗了性能,確實是這樣,是有一點性能損耗,用js生成一個js對象,他的代價是很是小的。可是用js生成一個dom元素,他的代價極高,爲何呢?底層的原理是,js生成dom會調用webapplication級別的一個api。這種級別的api性能損耗是比較大的。
舊的方案是數據 + 模板 結合,生成真實的dom,而在新的方案裏面不是這樣的,是數據+模板生成新的虛擬dom,這一步就極大的提高了性能。
舊的方式是新的dom(DocumentFragment) 和 原始的dom作比對。也就是dom層面的作對比,只要是dom層面的對比,他就是很耗性能,新的方式是比較原始虛擬DOM和新的虛擬DOM的區別,兩個js對象的比對是很是不消耗性能的
因此虛擬dom是減小了真實dom的建立以及真實dom的對比,取而代之,我建立的都是js對象,對比的也是js對象,用這種方式提高了性能
 
 
爲了方便理解,上面寫成先生成真實的dom,再生成虛擬dom,實際上這是反過來的,這點要從新的認識一下
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中的內容
講到這裏,以前你們會認爲jsx就是頁面上的dom,但實際上理解原理以後,就知道,他就是一個模板,以後會把這個模板跟state或者props作結合,結合完成以後,有個虛擬dom,有了虛擬dom以後,再生成真實dom。那麼jsx的代碼和真實的dom有什麼樣的關係呢?首先,jsx先變成了虛擬dom。也就是js對象。而後再被轉化成真實的dom。那麼jsx怎麼變成js對象呢,js對象you怎麼變成真實的dom。

好比 return(<div>item</div>),react底層其實會把jsx語法經過createElement變成js對象,而後再轉化真實的dom, return React.createElement('div',{},'item')。這兩種效果是一摸同樣的。React.createElement是更底層的一個東西,實際上會有一個js對象的東西傳遞給createElement,那麼這個方法實際拿到這個對象以後,直接變成了虛擬dom,而後渲染成真實的dom。因此是
jsx -> createElement -> 虛擬dom(js對象)-> 真實的dom
因此沒有jsx,也能夠去寫頁面,可是這樣會比較複雜,好比 return(<div><span></span></div>)須要寫成 return React.createElement('div',{},React.createElement('span',{},'item'))
因此jsx不是真實的dom,沒有這種語法,徹底能夠經過createElement實現jsx的功能。jsx之因此存在,是使代碼寫的方便,簡潔。Vue裏面也有一個虛擬dom,跟這個也是相似的。

那麼虛擬dom帶來什麼樣的好處,只有頁面須要渲染的時候,才生成真實的dom。
第一個性能提高了。dom的比對變成了js對象的比對
第二個它使得跨端應用得以實現。你們應該據說過React Native,咱們能夠經過React語法寫原生的應用,這個得益於虛擬dom的存在,假設沒有虛擬dom,一開始就是渲染真實的dom,渲染dom在瀏覽器上是沒有問題的,但是在移動端的原生應用裏面,好比安卓或ios機器上的代碼的時候,它裏面是不存在dom這個概念的,因此沒有虛擬dom,在原生的app裏面根本沒法被使用,因此代碼只能在瀏覽器裏面,可是有了虛擬dom就不同了,js對象能夠在瀏覽器裏面被識別,同時也能夠在原生應用裏面被識別,在瀏覽器裏面生成真實的dom,那麼在原生應用裏面能夠不讓他生成真實的dom,而是生成原生的組件,這樣state,jsx均可以被複用,由於生成的虛擬dom,在哪裏均可以運行。這使得react能夠開發網頁,也能夠開發原生應用。
相關文章
相關標籤/搜索