解析 React 虛擬 DOM 原理 + DOM Diff 算法

導讀:

  • 當用原生 JS / jQuery 操作 DOM 時藏杖,瀏覽器會從構(gòu)建 DOM 樹開始從頭到尾渲染一遍 DOM 節(jié)點,而大量的 DOM 操作會頻繁的更新 DOM( 即再次從頭到尾渲染 ),這無疑是非常消耗瀏覽器性能的,因此由 FaceBook 團隊提出的虛擬 DOM 橫空出世,并運用在了 React 之上( 目前 Vue 2.x 也引入了這個概念 )低缩,接下來我們就分析一下虛擬 DOM 的原理。

虛擬 DOM 原理:

  • 無虛擬 DOM 時曹货,React 中 DOM 的渲染流程:
    1. state 數(shù)據(jù)
    2. JSX 模板
    3. 數(shù)據(jù) + 模板 結(jié)合咆繁,生成真實的 DOM,來顯示
    4. state 發(fā)生改變
    5. 數(shù)據(jù) + 模板 結(jié)合顶籽,生成真實的 DOM玩般,替換原始的 DOM

缺陷:
第一次生成了一個完整的 DOM 片段
第二次生成了一個完整的 DOM 片段
第二次的 DOM 替換了第一次的 DOM,非常耗性能

  • React 優(yōu)化后礼饱,React 中 DOM 的渲染流程:
    1. state 數(shù)據(jù)
    2. JSX 模板
    3. 數(shù)據(jù) + 模板 結(jié)合坏为,生成真實的 DOM,來顯示
    4. state 發(fā)生改變
    5. 數(shù)據(jù) + 模板 結(jié)合镊绪,生成真實的 DOM匀伏,并不直接替換原始的 DOM
    6. 新的 DOM( DocumentFragment )和原來的 DOM 樹做對比,找差異( 耗性能 )
    7. 找出發(fā)生變化的節(jié)點
    8. 只能新的 DOM 中發(fā)生變化的節(jié)點替換掉老的 DOM 中的相應節(jié)點

缺陷:
性能提升并不明顯

  • 引入虛擬 DOM 后蝴韭,React 中 DOM 的渲染流程:
    1. state 數(shù)據(jù)
    2. JSX 模板
    3. 數(shù)據(jù) + 模板够颠,生成虛擬 DOM ( 虛擬 DOM 就是一個 JS 對象,用它來描述真實的 DOM )( 損耗了性能 )
      [ 'div', { id: "root" }, [ 'span', { }, 'hello world' ] ]
    4. 用虛擬 DOM 的結(jié)構(gòu)生成真實的 DOM榄鉴,來顯示
      <div id="root"><span>hello world</span></div>
    5. state 發(fā)生變化
    6. 數(shù)據(jù) + 模板 結(jié)合履磨,生成新的虛擬 DOM( 極大提升了性能 )
      [ 'div', { id: "root" }, [ 'span', { }, 'bye bye' ] ]
    7. 比較新的虛擬 DOM 和原始虛擬 DOM 的區(qū)別,找到區(qū)別是 span 中的內(nèi)容( 極大提升了性能 )
    8. 直接操作 DOM庆尘,改變 span 中的內(nèi)容
      總結(jié):JSX -> React.createElement -> 虛擬 DOM (JS對象)-> 真實的DOM

優(yōu)點:
性能提升
它使得跨端應用得以實現(xiàn)剃诅。React Native

DOM Diff 算法:

  • 首先當改變 state 數(shù)據(jù)時,由于 setState 是一個異步函數(shù)( 官方文檔原話:不保證它是同步的 )驶忌,這里關(guān)于異步的問題我們暫時這么理解矛辕,如果深究可以自行去其他博客學習,當你一次調(diào)用三次 setState 時位岔,React 并不會生成三次虛擬 DOM 而是將三次 setState 合并如筛,然后生成一次虛擬 DOM 進行比對堡牡,接下來:


  • 當新的虛擬 DOM 與原來的虛擬 DOM 進行比對時抒抬,它會進行同層比較,即相同的節(jié)點層進行比較晤柄,如果不同則直接將原始虛擬 DOM 中該節(jié)點層及以下的節(jié)點全部刪除擦剑,重新生成新的虛擬 DOM 節(jié)點,而不會繼續(xù)向下比對。


  • 這里順便提一點惠勒,當你在 JSX 模板中遍歷 state 中某個數(shù)據(jù)時赚抡,為什么不加 key 值瀏覽器會報錯,這是因為你不再遍歷的每條數(shù)據(jù)加上 key 值纠屋,更改 state 中那條數(shù)據(jù)的值涂臣,生成虛擬 DOM 后,React 就不知道原始遍歷的數(shù)據(jù)和這次更新后遍歷的數(shù)據(jù)一一對應的關(guān)系售担,就會再次重新渲染赁遗,而加上 key 值,它則能迅速比對出有差異的部分進行部分的更新族铆,但是為什么不建議用 index 作為 key 值呢岩四?因為當你插入 / 刪除中間的數(shù)據(jù)時,從改變的那個數(shù)據(jù)開始哥攘,后續(xù)每個數(shù)據(jù)的 index 值就會變剖煌,從而就導致了每個數(shù)據(jù)的 key 值相應變化了,這樣依舊會引起大規(guī)模渲染逝淹,這就是其中的原因啦耕姊。


總結(jié):

  • 這篇文章真的干貨滿滿,上面的內(nèi)容都是博主精心總結(jié)的创橄,建議各位讀者細讀箩做,必有大收獲!
  • Vue 2.x 的虛擬 DOM 原理和 DOM Diff算法與 React 的基本大同小異妥畏,一篇懂邦邦,全都懂!
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末醉蚁,一起剝皮案震驚了整個濱河市燃辖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌网棍,老刑警劉巖黔龟,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異滥玷,居然都是意外死亡氏身,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門惑畴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蛋欣,“玉大人,你說我怎么就攤上這事如贷∠莼ⅲ” “怎么了到踏?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長尚猿。 經(jīng)常有香客問我窝稿,道長,這世上最難降的妖魔是什么凿掂? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任伴榔,我火速辦了婚禮,結(jié)果婚禮上庄萎,老公的妹妹穿的比我還像新娘潮梯。我一直安慰自己,他們只是感情好惨恭,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布秉馏。 她就那樣靜靜地躺著,像睡著了一般脱羡。 火紅的嫁衣襯著肌膚如雪萝究。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天锉罐,我揣著相機與錄音帆竹,去河邊找鬼。 笑死脓规,一個胖子當著我的面吹牛栽连,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播侨舆,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼秒紧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了挨下?” 一聲冷哼從身側(cè)響起熔恢,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎臭笆,沒想到半個月后叙淌,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡愁铺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年鹰霍,在試婚紗的時候發(fā)現(xiàn)自己被綠了账蓉。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诺凡。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡尸昧,死狀恐怖伏蚊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情譬重,我是刑警寧澤医窿,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布仰担,位于F島的核電站在验,受9級特大地震影響玷氏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜腋舌,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一盏触、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧块饺,春花似錦赞辩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至淮腾,卻和暖如春糟需,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背谷朝。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工洲押, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人圆凰。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓杈帐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親专钉。 傳聞我的和親對象是個殘疾皇子挑童,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

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