React中一個(gè)沒人能解釋清楚的問題——為什么要使用Virtual DOM

譯者:TinkGu
鏈接:http://www.zcfy.cc/article/1211
原文:https://hashnode.com/post/the-one-thing-that-no-one-properly-explains-about-react-why-virtual-dom-cisczhfj41bmssp53mvfwmgrq

有一天波材,我的朋友向我提了一個(gè)有關(guān)React的問題:

組件化, 單向數(shù)據(jù)綁定,這些我都懂了。但是React為什么要用Virtual DOM呢霹购?

我的回答非常套路,“因?yàn)橹苯硬僮鱀OM比較低效融欧,比較慢咱圆。”羽利。

“但是現(xiàn)在的js引擎總是搞個(gè)大新聞宫患,說(shuō)自己的性能比之前又要不知道高到哪里去了。既然如此这弧,為什么還會(huì)說(shuō)直接操作DOM比較慢呢娃闲?”

好吧... 這確實(shí)是一個(gè)好問題。

驚人的是匾浪,我找了半天皇帮,發(fā)現(xiàn)并沒有任何一篇文章可以給出堅(jiān)如磐石的證明,來(lái)完滿地解釋Virtual DOM的必要性蛋辈。
其實(shí)属拾,使得整個(gè)流程變得低效的,并不只有直接操作DOM冷溶,還包括了操作DOM之后發(fā)生的事情渐白。

為了能讓你更好地理解Virtual DOM的必要性,我們先來(lái)個(gè)急轉(zhuǎn)彎逞频,從宏觀上來(lái)看瀏覽器的工作流纯衍。以及,一次DOM更新后苗胀,到底會(huì)發(fā)生什么事呢襟诸?

瀏覽器工作流

NOTE:在下面這張圖中,配圖文字使用的是Webkit引擎的術(shù)語(yǔ)基协。所有的瀏覽器都是遵循類似的工作流歌亲,僅在細(xì)節(jié)處略有不同。

瀏覽器工作流
瀏覽器工作流

創(chuàng)建DOM樹

  • 一旦瀏覽器接收到一個(gè)HTML文件堡掏,渲染引擎(render engine)就開始解析它应结,并根據(jù)HTML元素(elements)一一對(duì)應(yīng)地生成DOM 節(jié)點(diǎn)(nodes),組成一棵DOM樹泉唁。

創(chuàng)建渲染樹

  • 同時(shí)鹅龄,瀏覽器也會(huì)解析來(lái)自外部CSS文件和元素上的inline樣式。通常瀏覽器會(huì)為這些樣式信息亭畜,連同包含樣式信息的DOM樹上的節(jié)點(diǎn)扮休,再創(chuàng)建另外一個(gè)樹,一般被稱作渲染樹(render tree

創(chuàng)建渲染樹背后的故事

  • WebKit內(nèi)核的瀏覽器上拴鸵,處理一個(gè)節(jié)點(diǎn)的樣式的過程稱為attachment玷坠。DOM樹上的每個(gè)節(jié)點(diǎn)都有一個(gè)attach方法蜗搔,它接收計(jì)算好的樣式信息,返回一個(gè)render對(duì)象(又名renderer
  • Attachment的過程是同步的八堡,新節(jié)點(diǎn)插入DOM樹時(shí)樟凄,會(huì)調(diào)用新節(jié)點(diǎn)的attach方法。
  • 構(gòu)建渲染樹時(shí)兄渺,由于包含了這些render對(duì)象缝龄,每個(gè)render對(duì)象都需要計(jì)算視覺屬性(visual properties);這個(gè)過程通過計(jì)算每個(gè)元素的樣式屬性來(lái)完成挂谍。

布局 Layout

又被簡(jiǎn)稱為Reflow[2]

  • 構(gòu)造了渲染樹以后叔壤,瀏覽器引擎開始著手布局(layout)。布局時(shí)口叙,渲染樹上的每個(gè)節(jié)點(diǎn)根據(jù)其在屏幕上應(yīng)該出現(xiàn)的精確位置炼绘,分配一組屏幕坐標(biāo)值。

繪制 Painting

  • 接著妄田,瀏覽器將會(huì)通過遍歷渲染樹俺亮,調(diào)用每個(gè)節(jié)點(diǎn)的paint方法來(lái)繪制這些render對(duì)象。paint方法根據(jù)瀏覽器平臺(tái)形庭,使用不同的UI后端API(agnostic UI backend API)铅辞。
    通過繪制厌漂,最終將在屏幕上展示內(nèi)容萨醒。

再來(lái)看Virtual DOM

好啦,現(xiàn)在你已經(jīng)簡(jiǎn)單過了一遍瀏覽器引擎的渲染流程苇倡,你可以看到富纸,從創(chuàng)建渲染樹,到布局旨椒,一直到繪制晓褪,只要你在這過程中進(jìn)行一次DOM更新,整個(gè)渲染流程都會(huì)重做一遍综慎。尤其是創(chuàng)建渲染樹涣仿,它需要重新計(jì)算所有元素上的所有樣式。

在一個(gè)復(fù)雜的單頁(yè)面應(yīng)用中示惊,經(jīng)常會(huì)涉及到大量的DOM操作好港,這將引起多次計(jì)算,使得整個(gè)流程變得低效米罚,這應(yīng)該盡量避免钧汹。

Virtual DOM這個(gè)抽象層真正的閃光點(diǎn)正在于此:每當(dāng)你想對(duì)視圖進(jìn)行一次更新,那些本該直接作用于真實(shí)DOM的改動(dòng)录择,都會(huì)先作用于Virtual DOM拔莱,然后再將要改動(dòng)的部分通知到真實(shí)DOM碗降。這樣可以大幅減少DOM操作帶來(lái)的重計(jì)算步驟。

Update: Reddit上的 ugwe43to874nf4 對(duì)Virtual DOM的重要性做了更客觀的評(píng)價(jià)塘秦。

DOM 操作 真正的問題在于每次操作都會(huì)觸發(fā)布局的改變讼渊、DOM樹的修改和渲染。所以尊剔,當(dāng)你一個(gè)接一個(gè)地去修改30個(gè)節(jié)點(diǎn)的時(shí)候精偿,就會(huì)引起30次(潛在的)布局重算,30次(潛在的)重繪赋兵,等等笔咽。

Virtual DOM 實(shí)際上沒有使用什么全新的技術(shù),僅僅是把 “ 雙緩沖(double buffering)” 技術(shù)應(yīng)用到了DOM上面霹期。
這樣一來(lái)叶组,當(dāng)你在這個(gè)單獨(dú)的虛擬的DOM樹上也一個(gè)接一個(gè)地修改30個(gè)節(jié)點(diǎn)的時(shí)候,它不會(huì)每次都去觸發(fā)重繪历造,所以修改節(jié)點(diǎn)的開銷就變小了甩十。
之后,一旦你要把這些改動(dòng)傳遞給真實(shí)DOM吭产,之前所有的改動(dòng)就會(huì)整合成一次DOM操作侣监。這一次DOM操作引起的布局計(jì)算和重繪可能會(huì)更大,但是相比而言臣淤,整合起來(lái)的改動(dòng)只做一次橄霉,減少了(多次)計(jì)算。

不過邑蒋,實(shí)際上不借助Virtual DOM也可以做到這一點(diǎn)姓蜂。你可以自己手動(dòng)地整合所有的DOM操作到一個(gè)DOM 碎片(DOM fragment) 里,然后再傳遞給DOM樹医吊。

既然如此钱慢,我們?cè)賮?lái)看看Virtual DOM到底解決了什么問題。
首先卿堂,它把管理DOM碎片這件事情自動(dòng)化束莫、抽象化了,使得你無(wú)需再去手動(dòng)處理草描。另外览绿,當(dāng)你要手動(dòng)去做這件事情的時(shí)候,你還得記得哪些部分變化了陶珠,哪些部分沒變挟裂,畢竟之后重繪時(shí),DOM樹上的大量細(xì)節(jié)你都不需要重新刷新揍诽。這時(shí)候Virtual DOM的自動(dòng)化對(duì)你來(lái)說(shuō)就非常有用了诀蓉,如果它的實(shí)現(xiàn)是正確的栗竖,那么它就會(huì)知道到底哪些地方應(yīng)該需要刷新,哪些地方不要渠啤。

最后狐肢,Virtual DOM通過各種組件和你寫的一些代碼來(lái)請(qǐng)求對(duì)它進(jìn)行操作,而不是直接對(duì)它本身進(jìn)行操作沥曹,使你不必非要跟Virtual DOM交互份名,也不必非要去了解Virtual DOM修改DOM樹的原理,也就不用再想著去修改DOM了妓美。(譯注:對(duì)開發(fā)者來(lái)說(shuō)僵腺,Virtual DOM幾乎是完全透明的)。這樣你就不用在 修改DOM整合DOM操作為一次 之間做同步處理了壶栋。

進(jìn)一步閱讀

以上關(guān)于瀏覽器工作流的內(nèi)容摘錄自這篇文檔中關(guān)于瀏覽器內(nèi)部行為的章節(jié)辰如。這篇文章還深入解釋了瀏覽器引擎的hood部分的一切細(xì)節(jié)。毋庸置疑贵试,這篇文章值得你花時(shí)間從頭到尾好好讀一遍琉兜。它會(huì)幫你很好地理解為什么我們需要Virtual DOM這樣一個(gè)額外的抽象層。

譯注

  • [ 1 ] a 3000 feet level view 如果翻譯成 “一個(gè)達(dá)到30000英尺這種級(jí)別的視圖”毙玻,總覺得怪怪的豌蟋,于是翻譯為一個(gè)超大型的視圖。 如果哪位知道信達(dá)雅的翻譯桑滩,請(qǐng)?jiān)u論留言分享一下梧疲,謝謝!
  • [ 2 ] Webkit 里使用layout表示元素的布局施符,Gecko則稱為Reflow往声。
  • [ 3 ] 遵循慣例,文中一律將node(特指DOM樹上的一個(gè)單元)翻譯為節(jié)點(diǎn)戳吝;將element(特指HTML上的一個(gè)單元)翻譯為元素
  • [ 4 ] Virtual DOM虛擬 DOM贯涎√蓿考慮到這詞幾乎已經(jīng)稱為一個(gè)專門的術(shù)語(yǔ)了,一般大家也直接用英文稱呼塘雳,不翻譯可能更具可讀性陆盘。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市败明,隨后出現(xiàn)的幾起案子隘马,更是在濱河造成了極大的恐慌,老刑警劉巖妻顶,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酸员,死亡現(xiàn)場(chǎng)離奇詭異蜒车,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)幔嗦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門酿愧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人邀泉,你說(shuō)我怎么就攤上這事嬉挡。” “怎么了汇恤?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵庞钢,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我因谎,道長(zhǎng)焊夸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任蓝角,我火速辦了婚禮阱穗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘使鹅。我一直安慰自己揪阶,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布患朱。 她就那樣靜靜地躺著鲁僚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪裁厅。 梳的紋絲不亂的頭發(fā)上冰沙,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音执虹,去河邊找鬼拓挥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛袋励,可吹牛的內(nèi)容都是我干的侥啤。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼茬故,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼盖灸!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起磺芭,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤赁炎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后钾腺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體徙垫,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡讥裤,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了松邪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坞琴。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖逗抑,靈堂內(nèi)的尸體忽然破棺而出剧辐,到底是詐尸還是另有隱情,我是刑警寧澤邮府,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布荧关,位于F島的核電站,受9級(jí)特大地震影響褂傀,放射性物質(zhì)發(fā)生泄漏忍啤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一仙辟、第九天 我趴在偏房一處隱蔽的房頂上張望同波。 院中可真熱鬧,春花似錦叠国、人聲如沸未檩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)冤狡。三九已至,卻和暖如春项棠,著一層夾襖步出監(jiān)牢的瞬間悲雳,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工香追, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留合瓢,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓翅阵,卻偏偏與公主長(zhǎng)得像歪玲,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子掷匠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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