【前端100問】Q32:Virtual DOM 真的比操作原生 DOM 快嗎猫缭?談談你的想法麻养。

寫在前面

此系列來源于開源項目:前端 100 問:能搞懂 80%的請把簡歷給我
為了備戰(zhàn) 2021 春招
每天一題越庇,督促自己
從多方面多角度總結答案奋隶,豐富知識
Virtual DOM 真的比操作原生 DOM 快嗎?談談你的想法悦荒。
簡書整合地址:前端 100 問

正文回答

作者:尤雨溪

鏈接:https://www.zhihu.com/question/31809713/answer/53544875

來源:知乎

原生 DOM 操作 vs. 通過框架封裝操作。

這是一個性能 vs. 可維護性的取舍嘹吨“嵛叮框架的意義在于為你掩蓋底層的 DOM 操作,讓你用更聲明式的方式來描述你的目的,從而讓你的代碼更容易維護碰纬。沒有任何框架可以比純手動的優(yōu)化 DOM 操作更快萍聊,因為框架的 DOM 操作層需要應對任何上層 API 可能產生的操作,它的實現必須是普適的悦析。針對任何一個 benchmark寿桨,我都可以寫出比任何框架更快的手動優(yōu)化,但是那有什么意義呢强戴?在構建一個實際應用的時候亭螟,你難道為每一個地方都去做手動優(yōu)化嗎?出于可維護性的考慮骑歹,這顯然不可能预烙。框架給你的保證是道媚,你在不需要手動優(yōu)化的情況下扁掸,我依然可以給你提供過得去的性能。

對 React 的 Virtual DOM 的誤解最域。

React 從來沒有說過 “React 比原生操作 DOM 快”谴分。React 的基本思維模式是每次有變動就整個重新渲染整個應用。如果沒有 Virtual DOM镀脂,簡單來想就是直接重置 innerHTML牺蹄。很多人都沒有意識到,在一個大型列表所有數據都變了的情況下狗热,重置 innerHTML 其實是一個還算合理的操作... 真正的問題是在 “全部重新渲染” 的思維模式下钞馁,即使只有一行數據變了,它也需要重置整個 innerHTML匿刮,這時候顯然就有大量的浪費僧凰。

Virtual DOM render + diff 顯然比渲染 html 字符串要慢,但是熟丸!它依然是純 js 層面的計算训措,比起后面的 DOM 操作來說,依然便宜了太多光羞〖可以看到,innerHTML 的總計算量不管是 js 計算還是 DOM 操作都是和整個界面的大小相關纱兑,但 Virtual DOM 的計算量里面呀闻,只有 js 計算和界面大小相關,DOM 操作是和數據的變動量相關的潜慎。前面說了捡多,和 DOM 操作比起來蓖康,js 計算是極其便宜的。這才是為什么要有 Virtual DOM:它保證了 1)不管你的數據變化多少垒手,每次重繪的性能都可以接受蒜焊;2) 你依然可以用類似 innerHTML 的思路去寫你的應用。

MVVM vs. Virtual DOM

相比起 React科贬,其他 MVVM 系框架比如 Angular, Knockout 以及 Vue泳梆、Avalon 采用的都是數據綁定:通過 Directive/Binding 對象,觀察數據變化并保留對實際 DOM 元素的引用榜掌,當有數據變化時進行對應的操作优妙。MVVM 的變化檢查是數據層面的,而 React 的檢查是 DOM 結構層面的唐责。

MVVM 的性能也根據變動檢測的實現原理有所不同:Angular 的臟檢查使得任何變動都有固定的
O(watcher count) 的代價鳞溉;Knockout/Vue/Avalon 都采用了依賴收集,在 js 和 DOM 層面都是 O(change):

  • 臟檢查:scope digest O(watcher count) + 必要 DOM 更新 O(DOM change)
  • 依賴收集:重新收集依賴 O(data change) + 必要 DOM 更新 O(DOM change)

可以看到鼠哥,Angular 最不效率的地方在于任何小變動都有的和 watcher 數量相關的性能代價熟菲。但是!當所有數據都變了的時候朴恳,Angular 其實并不吃虧抄罕。依賴收集在初始化和數據變化的時候都需要重新收集依賴,這個代價在小量更新的時候幾乎可以忽略于颖,但在數據量龐大的時候也會產生一定的消耗呆贿。

MVVM 渲染列表的時候,由于每一行都有自己的數據作用域森渐,所以通常都是每一行有一個對應的 ViewModel 實例做入,或者是一個稍微輕量一些的利用原型繼承的 "scope" 對象,但也有一定的代價同衣。所以竟块,MVVM 列表渲染的初始化幾乎一定比 React 慢,因為創(chuàng)建 ViewModel / scope 實例比起 Virtual DOM 來說要昂貴很多耐齐。這里所有 MVVM 實現的一個共同問題就是在列表渲染的數據源變動時浪秘,尤其是當數據是全新的對象時,如何有效地復用已經創(chuàng)建的 ViewModel 實例和 DOM 元素埠况。假如沒有任何復用方面的優(yōu)化耸携,由于數據是 “全新” 的,MVVM 實際上需要銷毀之前的所有實例辕翰,重新創(chuàng)建所有實例夺衍,最后再進行一次渲染!這就是為什么題目里鏈接的 angular/knockout 實現都相對比較慢喜命。相比之下沟沙,React 的變動檢查由于是 DOM 結構層面的的畴,即使是全新的數據,只要最后渲染結果沒變尝胆,那么就不需要做無用功。

Angular 和 Vue 都提供了列表重繪的優(yōu)化機制护桦,也就是 “提示” 框架如何有效地復用實例和 DOM 元素含衔。比如數據庫里的同一個對象,在兩次前端 API 調用里面會成為不同的對象二庵,但是它們依然有一樣的 uid贪染。這時候你就可以提示 track by uid 來讓 Angular 知道,這兩個對象其實是同一份數據催享。那么原來這份數據對應的實例和 DOM 元素都可以復用杭隙,只需要更新變動了的部分∫蛎睿或者痰憎,你也可以直接 track by index 來進行 “原地復用”:直接根據在數組里的位置進行復用。在題目給出的例子里攀涵,如果 angular 實現加上 track byindex 的話铣耘,后續(xù)重繪是不會比 React 慢多少的。甚至在 dbmonster 測試中以故,Angular 和 Vue 用了 track by $index 以后都比 React 快: dbmon (注意 Angular 默認版本無優(yōu)化蜗细,優(yōu)化過的在下面)

性能比較也要看場合

在比較性能的時候,要分清楚初始渲染怒详、小量數據更新炉媒、大量數據更新這些不同的場合。Virtual DOM昆烁、臟檢查 MVVM吊骤、數據收集 MVVM 在不同場合各有不同的表現和不同的優(yōu)化需求。

Virtual DOM 為了提升小量數據更新時的性能善玫,也需要針對性的優(yōu)化水援,比如 shouldComponentUpdate 或是 immutable data。

總結

以上這些比較茅郎,更多的是對于框架開發(fā)研究者提供一些參考蜗元。主流的框架 + 合理的優(yōu)化,足以應對絕大部分應用的性能需求系冗。如果是對性能有極致需求的特殊情況奕扣,其實應該犧牲一些可維護性采取手動優(yōu)化:比如 Atom 編輯器在文件渲染的實現上放棄了 React 而采用了自己實現的 tile-based rendering;又比如在移動端需要 DOM-pooling 的虛擬滾動掌敬,不需要考慮順序變化惯豆,可以繞過框架的內置實現自己搞一個池磁。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市楷兽,隨后出現的幾起案子地熄,更是在濱河造成了極大的恐慌,老刑警劉巖芯杀,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件端考,死亡現場離奇詭異,居然都是意外死亡揭厚,警方通過查閱死者的電腦和手機却特,發(fā)現死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來筛圆,“玉大人裂明,你說我怎么就攤上這事√” “怎么了闽晦?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長粉寞。 經常有香客問我尼荆,道長,這世上最難降的妖魔是什么唧垦? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任捅儒,我火速辦了婚禮,結果婚禮上振亮,老公的妹妹穿的比我還像新娘巧还。我一直安慰自己,他們只是感情好坊秸,可當我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布麸祷。 她就那樣靜靜地躺著,像睡著了一般褒搔。 火紅的嫁衣襯著肌膚如雪阶牍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天星瘾,我揣著相機與錄音走孽,去河邊找鬼。 笑死琳状,一個胖子當著我的面吹牛磕瓷,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼困食,長吁一口氣:“原來是場噩夢啊……” “哼边翁!你這毒婦竟也來了?” 一聲冷哼從身側響起硕盹,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤符匾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后瘩例,有當地人在樹林里發(fā)現了一具尸體待讳,經...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年仰剿,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片痴晦。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡南吮,死狀恐怖,靈堂內的尸體忽然破棺而出誊酌,到底是詐尸還是另有隱情部凑,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布碧浊,位于F島的核電站涂邀,受9級特大地震影響,放射性物質發(fā)生泄漏箱锐。R本人自食惡果不足惜比勉,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望驹止。 院中可真熱鬧浩聋,春花似錦、人聲如沸臊恋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抖仅。三九已至坊夫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間撤卢,已是汗流浹背环凿。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留凸丸,地道東北人拷邢。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像屎慢,于是被迫代替她去往敵國和親瞭稼。 傳聞我的和親對象是個殘疾皇子忽洛,可洞房花燭夜當晚...
    茶點故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內容

  • 本文主要是自己對https://www.zhihu.com/question/31809713一貼中各位大神分享的...
    技術與健康閱讀 1,266評論 0 3
  • 前言 React 好像已經火了很久很久,以致于我們對于 Virtual DOM 這個詞都已經很熟悉了环肘,網上也有非常...
    NARUTO_86閱讀 17,169評論 6 65
  • 變化這件事談論頁面的變化之前欲虚,咱們先看下數據和頁面(視覺層面的頁面)的關系。數據是隱藏在頁面底下悔雹,通過渲染展示給用...
    Www劉閱讀 451評論 0 1
  • 參考文章:深度剖析:如何實現一個Virtual DOM 算法 作者:戴嘉華React中一個沒人能解釋清楚的問題——...
    waka閱讀 5,965評論 0 21
  • 漸變的面目拼圖要我怎么拼? 我是疲乏了還是投降了益涧? 不是不允許自己墜落锈锤, 我沒有滴水不進的保護膜。 就是害怕變得面...
    悶熱當乘涼閱讀 4,246評論 0 13