react 虛擬DOM及diff演算法

2021-10-09 11:41:37 字數 3263 閱讀 2975

在vue,react這些框架中,都是通過監聽資料的變化而相應的去渲染我們的檢視.但是如果每次修改資料就去操作一次dom樹,這在效能上無疑是大打折扣的.虛擬dom的出現就是為了解決這個問題,並且起到協調的作用.本質上就是在js和真實dom樹之間做了乙個快取,具體原理是:每次當資料發生變化時,渲染機制先在虛擬dom上去改變檢視,然後再跟實際dom樹作比較(作比較用到的是虛擬dom的diff演算法),再在實際dom上更新差異部分(也就是這個時候才去操作實際dom樹,渲染差異部分),這樣就減少了對實際dom樹的操作,達到效能優化的效果.

簡單理解為:虛擬dom樹其實是實際dom樹更改之前的參考物件,是js實際操作dom節點時與真實dom樹之間的乙個中介(快取).以達到減少對dom節點的頻繁無效的操作和效能優化的目的.

兩種方式:

1.純js (一般不用這種)

2.jsx

<

!doctype html>

"en"

>

"utf-8"

>

"viewport" content=

"width=device-width, initial-scale=1.0"

>

"">

<

/script>

"">

<

/script>

<

!-- 由於瀏覽器的js引擎不能直接解析jsx

.需要babel.js轉譯為純js** --

>

"">

<

/script>

react<

/title>

<

/head>

// 建立虛擬dom容器

"myvirt"

>

<

/div>

"myvirt2"

>

<

/div>

"text/babel"

>

// 使用jsx建立虛擬dom時,type不能少

// 純js建立虛擬dom 建立標籤 屬性 文字內容

var str = react.

createelement

('div',,

'js建立虛擬dom');

console.

log(str,

1234

)// 渲染虛擬dom:reactdom.render(virtualdom,containerdom)

reactdom.

render

(str,document.

getelementbyid

("myvirt"))

var text =

"我是jsx虛擬dom"

;var viturldiv =

"myvirt2"

>

<

/div>

// jsx建立虛擬dom

reactdom.

render

(viturldiv,document.

getelementbyid

("myvirt2"))

<

/script>

<

/body>

<

/html>

diff演算法:該演算法並不是react獨有的演算法,react只是在傳統diff演算法的基礎上做了一些優化而已.實現機制是:深度遍歷dom樹,從根節點開始優先查詢節點的左子樹及其左節點,完全遍歷完左子樹之後才會開始去查詢右子樹,查詢右子樹時也是先從右子樹的左節點開始往下查詢,直到遍歷完全.比較出兩棵樹之間的差異,然後在真實dom樹更新差異部分.

diff演算法的比較規則:

節點不存在,直接建立該節點;

節點存在且節點型別相同,繼而判斷屬性是否相同,不同則修改節點屬性,無需刪除該節點

節點存在且節點型別相同,繼而判斷文字內容是否相同,有差異則做出修改.

節點型別不同,直接刪除元素及其子節點,替換成新節點

兩個節點之間的差異包括:

1.直接替換原有節點

2.調整子節點,包括移動刪除等操作

3.修改節點屬性,文字內容

react diff:tree diff component diff element diff

官方建議不要出現跨層級的節點操作,當出現節點跨層級移動時,react並不會去移動節點,而是刪除要移動的節點及其子節點並重新建立到移動位置,

場景假設:

假如我有一千個節點,當我刪除第乙個節點時,那我要去更新剩下的999個節點的位置,針對相同的節點只是位置發生變化就會出現大量的刪除/建立節點的操作,這無疑會影響到react的效能.

*針對這一問題,react diff做出的優化措施是:*對同一層級的同組子節點(也就是父節點下的所有子節點)新增唯一的key來進行區分.

其實針對相同節點的操作,如果我有唯一的key值,我就根據這個key值去定位需要操作的節點,執行刪除操作即可,也不會影響到其他節點.如果要移動節點之間的位置,同理根據key值找到對應的節點,交換位置並更新為新的節點集合即可,其他節點不需要發生任何操作.這樣來達到優化.

key的作用主要是:

1.準確判斷除當前節點是否在舊集合中

2.極大的減少遍歷次數

當然也不是所有都加上key就是效能優化了,對於簡單列表頁渲染來說,不加key要比加了key的效能好.

例如:

>

1div

>

key=

"1">

1>

>

2div

>

key=

"2">

2>

>

3div

>

key=

"3">

3>

>

4div

>

key=

"4">

4>

>

5div

>

key=

"5">

5>

我如果要修改節點2跟4的位置,沒有key值的話我直接修改innertext即可.加了key值之後我需要去找到key=2的節點然後再找到key=4的節點,然後再將兩個節點調換位置.這樣移動dom節點的操作效能上就不如直接修改innertext.

所以,請注意不是加了key就一定優化效能.

參考大佬部落格:

React 虛擬 Dom 和 diff 演算法

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

react 虛擬DOM的diff演算法

1 state 資料 2 jsx模板 3 生成虛擬dom 虛擬dom就是乙個js物件,用它來描述真實dom div span hello world 通過這樣的乙個js物件,我們就可以表述上面的dom結構了 4 用虛擬dom的結構,生成真實的dom,來顯示 abc hello world span ...

react虛擬dom機制與diff演算法

react的乙個突出特點是擁有極速地渲染效能。該功能依靠的就是facebook研發團隊弄出的虛擬dom機制以及其獨特的diff演算法。下面簡單解釋一下react虛擬dom機制和diff演算法的實現思想 要講虛擬dom機制必須提到乙個概念 虛擬dom樹,這是react在真實dom樹基礎上建立的乙個抽象...