百摩网
当前位置: 首页 生活百科

dom的几种常见节点(虚拟DOM真的比操作原生DOM快吗)

时间:2023-07-13 作者: 小编 阅读量: 6 栏目名: 生活百科

出于可维护性的考虑,这显然不可能。MVVM的变化检查是数据层面的,而React的检查是DOM结构层面的。VirtualDOM、脏检查MVVM、数据收集MVVM在不同场合各有不同的表现和不同的优化需求。主流的框架合理的优化,足以应对绝大部分应用的性能需求。

尤雨溪:https://www.zhihu.com/question/31809713/answer/53544875

Virtual DOM 真的比操作原生 DOM 快吗?

1. 原生 DOM 操作 vs. 通过框架封装操作。

这是一个性能 vs. 可维护性的取舍。框架的意义在于为你掩盖底层的 DOM 操作,让你用更声明式的方式来描述你的目的,从而让你的代码更容易维护。没有任何框架可以比纯手动的优化 DOM 操作更快,因为框架的 DOM 操作层需要应对任何上层 API 可能产生的操作,它的实现必须是普适的。针对任何一个 benchmark,我都可以写出比任何框架更快的手动优化,但是那有什么意义呢?在构建一个实际应用的时候,你难道为每一个地方都去做手动优化吗?出于可维护性的考虑,这显然不可能。框架给你的保证是,你在不需要手动优化的情况下,我依然可以给你提供过得去的性能。

2. 对 React 的 Virtual DOM 的误解。

React 从来没有说过 “React 比原生操作 DOM 快”。React 的基本思维模式是每次有变动就整个重新渲染整个应用。如果没有 Virtual DOM,简单来想就是直接重置 innerHTML。很多人都没有意识到,在一个大型列表所有数据都变了的情况下,重置 innerHTML 其实是一个还算合理的操作... 真正的问题是在 “全部重新渲染” 的思维模式下,即使只有一行数据变了,它也需要重置整个 innerHTML,这时候显然就有大量的浪费。

我们可以比较一下 innerHTML vs. Virtual DOM 的重绘性能消耗:

  • innerHTML: render html string O(template size)重新创建所有 DOM 元素 O(DOM size)
  • Virtual DOM: render Virtual DOMdiff O(template size) 必要的 DOM 更新 O(DOM change)

Virtual DOM renderdiff 显然比渲染 html 字符串要慢,但是!它依然是纯 js 层面的计算,比起后面的 DOM 操作来说,依然便宜了太多。可以看到,innerHTML 的总计算量不管是 js 计算还是 DOM 操作都是和整个界面的大小相关,但 Virtual DOM 的计算量里面,只有 js 计算和界面大小相关,DOM 操作是和数据的变动量相关的。前面说了,和 DOM 操作比起来,js 计算是极其便宜的。这才是为什么要有 Virtual DOM:它保证了 ①不管你的数据变化多少,每次重绘的性能都可以接受;②你依然可以用类似 innerHTML 的思路去写你的应用。

3. 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 慢,因为创建 ViewModel / scope 实例比起 Virtual DOM 来说要昂贵很多。这里所有 MVVM 实现的一个共同问题就是在列表渲染的数据源变动时,尤其是当数据是全新的对象时,如何有效地复用已经创建的 ViewModel 实例和 DOM 元素。假如没有任何复用方面的优化,由于数据是 “全新” 的,MVVM 实际上需要销毁之前的所有实例,重新创建所有实例,最后再进行一次渲染!这就是为什么题目里链接的 angular/knockout 实现都相对比较慢。相比之下,React 的变动检查由于是 DOM 结构层面的,即使是全新的数据,只要最后渲染结果没变,那么就不需要做无用功。

Angular 和 Vue 都提供了列表重绘的优化机制,也就是 “提示” 框架如何有效地复用实例和 DOM 元素。比如数据库里的同一个对象,在两次前端 API 调用里面会成为不同的对象,但是它们依然有一样的 uid。这时候你就可以提示 track by uid 来让 Angular 知道,这两个对象其实是同一份数据。那么原来这份数据对应的实例和 DOM 元素都可以复用,只需要更新变动了的部分。或者,你也可以直接 track by $index 来进行 “原地复用”:直接根据在数组里的位置进行复用。在题目给出的例子里,如果 angular 实现加上 track by $index 的话,后续重绘是不会比 React 慢多少的。甚至在 dbmonster 测试中,Angular 和 Vue 用了 track by $index 以后都比 React 快: dbmon (注意 Angular 默认版本无优化,优化过的在下面)

顺道说一句,React 渲染列表的时候也需要提供 key 这个特殊 prop,本质上和 track-by 是一回事。

4. 性能比较也要看场合

在比较性能的时候,要分清楚初始渲染、小量数据更新、大量数据更新这些不同的场合。Virtual DOM、脏检查 MVVM、数据收集 MVVM 在不同场合各有不同的表现和不同的优化需求。Virtual DOM 为了提升小量数据更新时的性能,也需要针对性的优化,比如 shouldComponentUpdate 或是 immutable data。

  • 初始渲染:Virtual DOM > 脏检查 >= 依赖收集
  • 小量数据更新:依赖收集 >> Virtual DOM优化 > 脏检查(无法优化) > Virtual DOM 无优化
  • 大量数据更新:脏检查优化 >= 依赖收集优化 > Virtual DOM(无法/无需优化)>> MVVM 无优化

不要天真地以为 Virtual DOM 就是快,diff 不是免费的,batching 么 MVVM 也能做,而且最终 patch 的时候还不是要用原生 API。在我看来 Virtual DOM 真正的价值从来都不是性能,而是它 ① 为函数式的 UI 编程方式打开了大门;② 可以渲染到 DOM 以外的 backend,比如 ReactNative。

5. 总结

以上这些比较,更多的是对于框架开发研究者提供一些参考。主流的框架合理的优化,足以应对绝大部分应用的性能需求。

,
    推荐阅读
  • 夏季竹芋为何不长叶子(在家里养观赏竹芋几年后)

    如果不及时将盆栽观赏竹芋搬到暖和一点的地方,剪掉冻伤的茎叶,它的根茎都会被冻伤,最终会导致根部腐烂。增加湿度的方案有很多种,最简单粗暴的就是在观赏竹芋的周围喷雾状水。要注意定期喷洒。而过多的水分就会导致叶子根系腐烂,叶子也会出现折叠的情况。在冬天温度较低的时候要控制浇水,这时观赏竹芋会陷入休眠。还有一种情况会导致叶子卷曲,那就是水的质量不好,如果长期直接用自来水给观赏竹芋补充水分。

  • 小米南瓜粥怎么熬好喝(小米南瓜粥淡甜绵滑)

    小米南瓜粥淡甜绵滑查看小米南瓜粥的做法大全天冷就来一碗暖胃的小米南瓜粥吧,低热量好消化,含有丰富的营养,淡甜绵滑的南瓜入口即化,香甜的味道在口中来回流动,舀上一勺粘稠软烂的小米粥满屋飘香,清新怡人,喝上一碗瞬间暖心肠!。

  • 南水北调中线水量多少(了解南水北调工程)

    南水北调中线水量多少南水北调中线工程从陶岔渠首调水入渠水量达到150亿立方米,沿线水资源配置进一步优化。中线工程惠及北京、天津、石家庄、郑州等沿线19座大中城市,5310万居民喝上了南水北调水。其中,北京1100万人,天津900万人,河北1510万人,河南1800万人。南水北调中线工程通水3年多来,北京、天津、河北、河南沿线受水省市供水安全系数有效提升,居民用水水质明显改善。

  • 羽绒服油渍要怎么洗得掉(羽绒服上的陈年油渍怎么去除)

    羽绒服是手洗还是干洗建议手洗。所以,在挑选羽绒服的时候不要只看厚不厚,首先要考虑上面几个因素。

  • 存在感很强的穿越小说(四本穿越异界搞科技变强的爽文)

    四本穿越异界搞科技变强的爽文1.《重型装甲龙要做憎恶》——作者:未落简评:科学奇幻文主角本来是个发育不良孵化失败的龙蛋,偶然吸收了地球穿越者信息体才得以破壳而出成为一只拥有穿越者记忆的钨龙雏龙,又因为没有父母的庇护在魔兽横行的森。

  • 传统的清明团子做法(只用糯米粉就错了)

    在这个春暖花开、万物复苏的日子里,碧绿清香的艾草已悄然遍布田间地头,用新鲜艾叶制作的糍粑是清明节的传统美食,也是客家独特的清明文化。清明前后,客家人几乎每家每户都有吃艾糍的习惯。面粉和糯米粉混合在一起,分几次倒入艾叶泥,揉成柔软不开裂、不沾手的面团。

  • 行走的满分作文语录(考场优秀作文守圣心)

    君子选择化解矛盾,损己利他。但作者直接指出这种选择是伪君子,再明确真正君子的所为。这样的君子心怀己利,却无处伸张施展。只能在利益冲突前,让出属于自己的合理“蛋糕”。通过举例论证否定这种一般认知,进一步收窄“君子”的概念。可坚守的目的正在于倡导,集腋成裘,社会道德重建将计日程功,礼的环境重塑亦指日可待。用“可”转折,指出困境下坚守儒道的重要性。这可能影响了教师的评分。

  • 一个人坚强久了也有累的时候(当一个人坚强久了)

    人生中会有很多时刻,只想大哭一场。因为在人前总是故作坚强、若无其事的样子,坚强久了,就背上了盔甲,带上了枷锁。脸上风轻云淡,表面若无其事,背后却偷偷流泪,自我疗伤。希望有个人能懂自己,能一眼看穿自己伪装的坚强。她们不是生来就坚强,而是习惯了一个人面对所有,一个人死撑硬扛。余生很长,愿你可以自己一个人扛,也有人心疼你的坚强。

  • 别克汽车网站首页(以领先科技开启MPV智享新纪元)

    标志其正式上市交付已进入冲刺阶段。定位于高端豪华旗舰MPV,别克世纪CENTURY采用了别克全新“三色盾”标识及PUREDesign纯粹设计理念,并采用双色车身设计,彰显豪华尊贵气度。此次凭借着豪华的车辆设计、智慧的人车交互,别克世纪CENTURY将豪华MPV的定义再次拉升到了全新的高度。根据近期中国汽车流通协会发布的报告显示,别克GL8三年保值率位列主流国产MPV市场榜首。

  • 果蔬酱是怎么做的(怎么做果蔬酱)

    百合2个,芒果1个,黄瓜1根,紫甘蓝1/4个,今天小编就来说说关于果蔬酱是怎么做的?下面更多详细答案一起来看看吧!百合剥去外层的枯瓣,洗净;芒果去皮、去核切成2厘米见方的小块;黄瓜去皮,切成与芒果同等大小的块;紫甘蓝撕成圆片状。将加工好的所有材料混合,装入密封盒中,放冰箱冷藏30分钟。取一小碗,将适量的色拉酱与番茄酱,倒入混合的果蔬中,充分拌匀。