React 虛擬 Dom 和 diff 算法

React將DOM抽象為虛擬DOM, 然后通過(guò)新舊虛擬DOM 這兩個(gè)對(duì)象的差異(Diff算法),最終只把變化的部分重新渲染,提高渲染效率的過(guò)程; (概念講完再描述一遍)

JS對(duì)象2Html.png
JS對(duì)象2HTML完整版.png
虛擬DOM的算法步驟.png

一句話: 用 JS 對(duì)象的形式,來(lái)表現(xiàn)一棵真是的 DOM 樹(shù);


Diff 算法

    • 當(dāng)你實(shí)際開(kāi)發(fā)使用React的時(shí)候,在某個(gè)時(shí)間點(diǎn) render() 函數(shù)創(chuàng)建了一棵React元素樹(shù),也就模擬一個(gè)虛擬 DOM 樹(shù)号枕,
    • 在下一個(gè)state或者props更新的時(shí)候储藐,render() 函數(shù)將創(chuàng)建一棵新的React元素樹(shù), 也就模擬了一個(gè)新的虛擬 DOM 樹(shù)再来,
    • 既然模擬出了新舊兩棵DOM 樹(shù), 那么如何高效的進(jìn)行新舊兩棵樹(shù)的對(duì)比呢??
    • 當(dāng)然是使用 DIff 算法...
  1. 傳統(tǒng)的 Diff 算法也是一直都有的;

    • 但是它的時(shí)間復(fù)雜度為O(n^3)
      意思是: 在React中更新10個(gè)元素則需要進(jìn)行1000次的比較鸽斟。(1000個(gè)===10億)
  2. React 通過(guò)制定大膽的策略琢歇,將 O(n^3) 復(fù)雜度的問(wèn)題轉(zhuǎn)換成 O(n^1=n) 復(fù)雜度的問(wèn)題育韩。

      1. 兩個(gè)不同類型的元素會(huì)產(chǎn)生不同的樹(shù) <MyTest /> 和 <MyComponent />
      1. 對(duì)于同一層級(jí)的一組子節(jié)點(diǎn)擦酌,它們可以通過(guò)唯一 key 進(jìn)行區(qū)分
    • 基于以上兩個(gè)前提策略宵晚,React 分別對(duì) tree diff、component diff 以及 element diff 三種 diff 方法是 進(jìn)行算法優(yōu)化维雇,
    • 下面介紹優(yōu)化后的幾種算法

Tree Diff

概念: 將新舊兩顆虛擬 DOM 樹(shù),按照層級(jí)對(duì)應(yīng)的關(guān)系,從頭到尾的遍歷一遍,,就能找到那些元素是需要更新的,這種方式: Tree Diff

Tree Diff 01.png
1 只會(huì)對(duì)相同顏色方框內(nèi)(同級(jí))的DOM節(jié)點(diǎn)進(jìn)行比較淤刃,即同一父節(jié)點(diǎn)下的所有子節(jié)點(diǎn)
2 當(dāng)發(fā)現(xiàn)節(jié)點(diǎn)已經(jīng)不存在,則該節(jié)點(diǎn)及其子節(jié)點(diǎn)會(huì)被完全刪除掉吱型,不會(huì)用于進(jìn)一步的比較
Tree Diff 02.png
  • 執(zhí)行過(guò)程:create A -> create B -> create C -> delete A

Component Diff

不同組件之間的對(duì)比
概念: 在對(duì)比每一個(gè)層級(jí)的時(shí)候,會(huì)有自己的組件,這種組件的對(duì)比方式就叫: Component Diff ;

? 這種對(duì)比方法其實(shí)比較的就是類型.↓↓↓

  • 如果類型相同,暫時(shí)不更新,
  • 如果類型不相同,就需要更新; ( 刪除舊的組件,再創(chuàng)建一個(gè)新的組件,插入到刪除組件的那個(gè)位置)
Component Diff 01.png
  • 執(zhí)行過(guò)程:delete D -> create G

Element Diff

同一層級(jí)中元素之間的對(duì)比
概念: 在類型相同的組件內(nèi), 再繼續(xù)對(duì)比組件內(nèi)部的元素,查看內(nèi)部元素是否相同,如果需要修改,找到需要修改的元素,進(jìn)行針對(duì)性的修改! 這種方式就叫: Element Diff

三種節(jié)點(diǎn)操作:
1 INSERT_MARKUP(插入)
2 MOVE_EXISTING(移動(dòng))
3 REMOVE_NODE(刪除)

INSERT_MARKUP:新的 component 類型不在老集合里逸贾,需要對(duì)新節(jié)點(diǎn)執(zhí)行插入操作。

MOVE_EXISTING:老的集合包含新的 component 類型津滞,就需要做移動(dòng)操作铝侵,可以復(fù)用以前的 DOM 節(jié)點(diǎn)。

REMOVE_NODE:老的 component 不在新集合里的触徐,需要執(zhí)行刪除操作 或者 老的 component 類型在新集合里也有咪鲜,但對(duì)應(yīng)的 element 不同則不能直接復(fù)用和更新,需要執(zhí)行刪除操作
Element Diff 01.png
  • 執(zhí)行過(guò)程:B != A锌介,則創(chuàng)建并插入 B嗜诀,刪除 A;以此類推孔祸,創(chuàng)建并插入 A、D发皿、C崔慧,刪除 B、C穴墅、D


    Element Diff 02.png
  • 執(zhí)行過(guò)程:B惶室、D 不做任何操作,A玄货、C 進(jìn)行移動(dòng)操作


diff 算法總結(jié):

  1. 保持完整的結(jié)構(gòu),有利于性能的提升

  2. 盡量使用相同類型的組件

  3. 在進(jìn)行 Element 或Component 級(jí)別對(duì)比的時(shí)候,為了提高對(duì)比的效率, React 推薦我們?yōu)槊總€(gè) for 循環(huán)創(chuàng)建出來(lái)的元素或者組件,提供一個(gè)唯一的 key;

  4. Tree diff :將新舊兩棵 DOM 樹(shù),按照層級(jí)對(duì)應(yīng)的關(guān)系,這樣只需要對(duì)樹(shù)進(jìn)行一次遍歷,就能夠找到哪些元素是需要更新的;

  5. Component Diff: 在對(duì)比每一層的時(shí)候,每一層都有自己的組件, 那么組件之間的對(duì)比,叫做 Component diff , 對(duì)比的方式,就是查看兩個(gè)組件的類型是否相同,如果相同,則暫時(shí)認(rèn)為不需要更新,如果類型不同,則表示更新(先把舊的組件刪除,再創(chuàng)建一個(gè)新的組件,插入到剛才刪除的位置);

  6. Element Diff:如果新舊 DOM 樹(shù)中的組件類型相同,會(huì)繼續(xù)比較這兩個(gè)組件內(nèi)部的元素是否也相同,如果元素發(fā)生了改變,則找到需要修改的元素,有針對(duì)性的修改,這種組件內(nèi)部元素級(jí)別的對(duì)比叫: Element Diff;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末皇钞,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子松捉,更是在濱河造成了極大的恐慌夹界,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件隘世,死亡現(xiàn)場(chǎng)離奇詭異可柿,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)丙者,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門复斥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人械媒,你說(shuō)我怎么就攤上這事目锭。” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵痢虹,是天一觀的道長(zhǎng)键俱。 經(jīng)常有香客問(wèn)我,道長(zhǎng)世分,這世上最難降的妖魔是什么编振? 我笑而不...
    開(kāi)封第一講書人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮臭埋,結(jié)果婚禮上踪央,老公的妹妹穿的比我還像新娘。我一直安慰自己瓢阴,他們只是感情好畅蹂,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般茫打。 火紅的嫁衣襯著肌膚如雪矫膨。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 52,682評(píng)論 1 312
  • 那天少漆,我揣著相機(jī)與錄音,去河邊找鬼硼被。 笑死示损,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的嚷硫。 我是一名探鬼主播检访,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼仔掸!你這毒婦竟也來(lái)了脆贵?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤起暮,失蹤者是張志新(化名)和其女友劉穎卖氨,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鞋怀,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡双泪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了密似。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片焙矛。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖残腌,靈堂內(nèi)的尸體忽然破棺而出村斟,到底是詐尸還是另有隱情贫导,我是刑警寧澤,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布蟆盹,位于F島的核電站孩灯,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏逾滥。R本人自食惡果不足惜峰档,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望寨昙。 院中可真熱鬧讥巡,春花似錦、人聲如沸舔哪。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)捉蚤。三九已至抬驴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間缆巧,已是汗流浹背布持。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留盅蝗,地道東北人鳖链。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像墩莫,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子逞敷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容