如果一次网页操作本身就只会触发一次回流/重绘,那么虚拟 dom 还有优势吗?

按照我目前的理解,虚拟dom的优势在于把当前的变化打包给浏览器,让浏览器一次性更新,而不是来一个更新一个,减少页面的回流和重绘.

但是如果只有一个按钮, 点一下文字变色或者改变某个元素的显隐性,那么这种操作浏览器应该本身就是只回流/重绘一次,这个时候虚拟dom还有优势吗?

还有个小问题: 默认浏览器是怎么更新元素的?

  1. 如果我一次 display:none 了页面中的9个元素,那么在没有虚拟dom的情况下,浏览器会回流/重绘9次吗
  2. 虚拟dom把产生的"补丁包"推给浏览器,有多个元素发生了变化,浏览器是怎么把他们渲染出来的,重新生成DOMCSSOM

先谢谢大佬!!!

阅读 5.2k
6 个回答

Q1:

但是如果只有一个按钮, 点一下文字变色或者改变某个元素的显隐性,那么这种操作浏览器应该本身就是只回流/重绘一次,这个时候虚拟 DOM 还有优势吗?

那肯定是原生直接操作 DOM 更快。

但问题是这种简单页面的场景为啥你要用 MVVM 框架?

P.S. 推荐看这篇尤大亲自答:https://www.zhihu.com/questio...


Q2:

如果我一次 display:none 了页面中的 9 个元素,那么在没有虚拟 DOM 的情况下,浏览器会回流/重绘 9 次吗。

这里的“一次”,我理解为是一段代码里连续控制 9 个元素隐藏,类似:

el1.style.display = 'none';
el2.style.display = 'none';
el3.style.display = 'none';
// 略...

那么答案是不一定。

老浏览器的话是回流 9 次(没错,就说你呢,明天就要退休的 IE)。现代浏览器会有渲染队列来对这种场景做优化,一段时间内的重复回流操作会被合并(但要注意这里的队列可能会被另一些操作打断并清空,比如 getBoundingClientRectgetComputedStyle 等等,这也很好理解,这些操作是要获取当前 DOM 状态的,自然要必须强制触发一次回流才可以拿到实时状态)。

而回流必然会重绘,重绘不一定回流。所以次数这里两者是一样的。


Q3:

虚拟 DOM 把产生的"补丁包"推给浏览器,有多个元素发生了变化,浏览器是怎么把他们渲染出来的,重新生成 DOM 和 CSSOM 吗?

这个问题太大了,三两句话说不清。先占坑,等有时间了补。

1.虚拟DOM这种方式,中间是多了一层JS的计算,diff优化。在现代网页中,由于页面布局复杂,元素较多,所以这种方式能解决一些重复渲染、UI阻塞等问题。

但从理论上来说,如果我自己知道哪些DOM需要更新,什么时候更新,那么直接原生操作效率肯定是最高的,中间不需要多一层计算。如果页面非常简单,就几个div,几张图片,不需要用上vue/react类的框架。相信我,只要你的代码不够烂,渲染效率比框架高是没有任何问题的。

但是如果你的页面很复杂,交互联动很多,涉及到多处更新等,你需要这里判断一下,那里判断一下,才能精确控制DOM的更新。这就导致一般人无法写出最优效率的代码。所以我认为虚拟DOM就是用来解决这个问题的,它帮你完成了你需要做的判断,并且在自己的框架体系下达到了最优解。比如vue,当你用模板语法的时候,效率是比用jsx高的。

2.关于浏览器工作原理的部分,首先要清楚有个规范在约束浏览器厂商,浏览器都会根据W3C/ECMA的规范来实现功能,具体的实现细节可能不一样,但是最终的效果是一样的。所以看网上的一些回答可能并不是准确的,浏览器也会一直优化自己的渲染效率。建议先看规范,其次看浏览器自己的实现。

这里就涉及到,只要是规范没有明确的东西,浏览器完全可以自己操作,这也就是为什么现在基本上就firefox和chrome家族(使用chromium的浏览器)一统天下了(因为他们的操作太牛逼,IE甘拜下风)。所以你所说的问题,我并不确定是否规范中有规定,如果没有明确规定,那么直接看浏览器的实现或许是最好的。
比如Chrome是Blink,Compositing in Blink / WebCore: From WebCore::RenderLayer to cc:Layer

我觉得大多数人都能针对特定例子,写出性能超过框架的代码。

但是你的精力损耗呢?框架一般都自带社区,社区活跃度也是选择框架的一个理由。

举个例子,针对长列表,在原生和 vue 中并没有什么差别。当我们需要做优化的时候,vue 有开源的虚拟列表组件,原生呢?对,我的确可以手写一个虚拟列表。但是一个是十分钟,一个是一个小时。


抛开上面讲到的特例,我不知道你给其他人 CR 过代码嘛?你无法保证每个人都会手动的优化代码,那么隔离 dom 操作,交由框架统一处理,也是降低心智,提升性能的一种办法

已参与了 SegmentFault 思否社区 10 周年「问答」打卡 ,欢迎正在阅读的你也加入。

尤雨溪在知乎的一个回答你可以看看,会给你一些启发:
尤雨溪知乎回答

你的小问题:
1.一次;
2.虚拟dom比对后最后还是会去操作dom,

1)旧的有,新的没有,那就是删除;(删除dom涉及回流,回流必定重绘)
2)旧的没有,新的有,那就是新增;(新增dom设计回流,回流必定重绘)
3)新旧都有那就是更新。(可能回流也可能只是重绘,比如只是背景色变了)

以上,如果错误,还请指正~

已参与了 SegmentFault 思否社区 10 周年「问答」打卡 ,欢迎正在阅读的你也加入。

楼上的回答学习了。不过我想说的是伪命题有意思吗,干脆说页面完全不重绘那用虚拟dom干什么不就好了吗?
这根本不是虚拟dom的问题,所有功能都是为了解决问题才开发的,你没这个问题就不用这个功能,需要讲为什么吗?难道取个当前时间我非要加载moment吗?

已参与了 SegmentFault 思否社区 10 周年「问答」打卡 ,欢迎正在阅读的你也加入。

没有什么框架能比原生性能更好,但很多时候都取决于开发者的个人水平。
而框架可以让整体的性能处于可接收范围之内,而且更容易维护。
虚拟dom 只是让 dom 更新写起来更加容易而已

推荐问题
宣传栏