React中一个没人能解释清楚的问题——为什么要使用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

有一天,我的朋友向我提了一个有关React的问题:

组件化, 单向数据绑定,这些我都懂了。但是React为什么要用Virtual DOM呢?

我的回答非常套路,“因为直接操作DOM比较低效,比较慢。”。

“但是现在的js引擎总是搞个大新闻,说自己的性能比之前又要不知道高到哪里去了。既然如此,为什么还会说直接操作DOM比较慢呢?”

好吧... 这确实是一个好问题。

惊人的是,我找了半天,发现并没有任何一篇文章可以给出坚如磐石的证明,来完满地解释Virtual DOM的必要性。
其实,使得整个流程变得低效的,并不只有直接操作DOM,还包括了操作DOM之后发生的事情。

为了能让你更好地理解Virtual DOM的必要性,我们先来个急转弯,从宏观上来看浏览器的工作流。以及,一次DOM更新后,到底会发生什么事呢?

浏览器工作流

NOTE:在下面这张图中,配图文字使用的是Webkit引擎的术语。所有的浏览器都是遵循类似的工作流,仅在细节处略有不同。

浏览器工作流
浏览器工作流

创建DOM树

  • 一旦浏览器接收到一个HTML文件,渲染引擎(render engine)就开始解析它,并根据HTML元素(elements)一一对应地生成DOM 节点(nodes),组成一棵DOM树。

创建渲染树

  • 同时,浏览器也会解析来自外部CSS文件和元素上的inline样式。通常浏览器会为这些样式信息,连同包含样式信息的DOM树上的节点,再创建另外一个树,一般被称作渲染树(render tree

创建渲染树背后的故事

  • WebKit内核的浏览器上,处理一个节点的样式的过程称为attachment。DOM树上的每个节点都有一个attach方法,它接收计算好的样式信息,返回一个render对象(又名renderer
  • Attachment的过程是同步的,新节点插入DOM树时,会调用新节点的attach方法。
  • 构建渲染树时,由于包含了这些render对象,每个render对象都需要计算视觉属性(visual properties);这个过程通过计算每个元素的样式属性来完成。

布局 Layout

又被简称为Reflow[2]

  • 构造了渲染树以后,浏览器引擎开始着手布局(layout)。布局时,渲染树上的每个节点根据其在屏幕上应该出现的精确位置,分配一组屏幕坐标值。

绘制 Painting

  • 接着,浏览器将会通过遍历渲染树,调用每个节点的paint方法来绘制这些render对象。paint方法根据浏览器平台,使用不同的UI后端API(agnostic UI backend API)。
    通过绘制,最终将在屏幕上展示内容。

再来看Virtual DOM

好啦,现在你已经简单过了一遍浏览器引擎的渲染流程,你可以看到,从创建渲染树,到布局,一直到绘制,只要你在这过程中进行一次DOM更新,整个渲染流程都会重做一遍。尤其是创建渲染树,它需要重新计算所有元素上的所有样式。

在一个复杂的单页面应用中,经常会涉及到大量的DOM操作,这将引起多次计算,使得整个流程变得低效,这应该尽量避免。

Virtual DOM这个抽象层真正的闪光点正在于此:每当你想对视图进行一次更新,那些本该直接作用于真实DOM的改动,都会先作用于Virtual DOM,然后再将要改动的部分通知到真实DOM。这样可以大幅减少DOM操作带来的重计算步骤。

Update: Reddit上的 ugwe43to874nf4 对Virtual DOM的重要性做了更客观的评价。

DOM 操作 真正的问题在于每次操作都会触发布局的改变、DOM树的修改和渲染。所以,当你一个接一个地去修改30个节点的时候,就会引起30次(潜在的)布局重算,30次(潜在的)重绘,等等。

Virtual DOM 实际上没有使用什么全新的技术,仅仅是把 “ 双缓冲(double buffering)” 技术应用到了DOM上面。
这样一来,当你在这个单独的虚拟的DOM树上也一个接一个地修改30个节点的时候,它不会每次都去触发重绘,所以修改节点的开销就变小了。
之后,一旦你要把这些改动传递给真实DOM,之前所有的改动就会整合成一次DOM操作。这一次DOM操作引起的布局计算和重绘可能会更大,但是相比而言,整合起来的改动只做一次,减少了(多次)计算。

不过,实际上不借助Virtual DOM也可以做到这一点。你可以自己手动地整合所有的DOM操作到一个DOM 碎片(DOM fragment) 里,然后再传递给DOM树。

既然如此,我们再来看看Virtual DOM到底解决了什么问题。
首先,它把管理DOM碎片这件事情自动化、抽象化了,使得你无需再去手动处理。另外,当你要手动去做这件事情的时候,你还得记得哪些部分变化了,哪些部分没变,毕竟之后重绘时,DOM树上的大量细节你都不需要重新刷新。这时候Virtual DOM的自动化对你来说就非常有用了,如果它的实现是正确的,那么它就会知道到底哪些地方应该需要刷新,哪些地方不要。

最后,Virtual DOM通过各种组件和你写的一些代码来请求对它进行操作,而不是直接对它本身进行操作,使你不必非要跟Virtual DOM交互,也不必非要去了解Virtual DOM修改DOM树的原理,也就不用再想着去修改DOM了。(译注:对开发者来说,Virtual DOM几乎是完全透明的)。这样你就不用在 修改DOM整合DOM操作为一次 之间做同步处理了。

进一步阅读

以上关于浏览器工作流的内容摘录自这篇文档中关于浏览器内部行为的章节。这篇文章还深入解释了浏览器引擎的hood部分的一切细节。毋庸置疑,这篇文章值得你花时间从头到尾好好读一遍。它会帮你很好地理解为什么我们需要Virtual DOM这样一个额外的抽象层。

译注

  • [ 1 ] a 3000 feet level view 如果翻译成 “一个达到30000英尺这种级别的视图”,总觉得怪怪的,于是翻译为一个超大型的视图。 如果哪位知道信达雅的翻译,请评论留言分享一下,谢谢!
  • [ 2 ] Webkit 里使用layout表示元素的布局,Gecko则称为Reflow
  • [ 3 ] 遵循惯例,文中一律将node(特指DOM树上的一个单元)翻译为节点;将element(特指HTML上的一个单元)翻译为元素
  • [ 4 ] Virtual DOM虚拟 DOM。考虑到这词几乎已经称为一个专门的术语了,一般大家也直接用英文称呼,不翻译可能更具可读性。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容