学习 React 过程中,发现很多文章说到: 为什么要用 VDOM ,而不是直接操作真实 DOM ?都有类似这样的表述:直接操作真实 DOM 耗性能,细小的改动都可能导致重绘或重排。
但是如下这样直接操作 DOM ,不比用 VDOM 然后 Diff 后更新 DOM 性能更好吗?
document.getElementById("divId").innerHTML = "update text";

使用 VDOM 的目的更多的是便于管理更新,而不是性能上的考虑?

存在批量修改的情况下,VDOM 可以批量再内存中完成修改,再同步到 DOM 上;

如果这个操作在短时间内做 1000 次,最后再把它改回原样,用 VDOM 就可以绕过所有重排和绘制工作
许多页面的生成过程,并不能像这个例子一样一步到位

就问你怎么根据应用状态更新 DOM 吧,要么精细操作,DOM 操作会到处散落且有大量重复片段,要么直接简单无脑全量刷新。
即不想要手动精细操作,又不想低效全量更新 DOM,那只有 VDOM 或类 solidjs 这种,很明显性能比原始全量更新性能高。

不谈量级的话这种说法不妥

其实就是性能与可维护性的均衡。
声明式的更新性能消耗( vue ,react )= 找出差异的性能消耗 ( diff ,vdom )+ 直接修改的性能消耗( document.createElement 等)。只是目前结合心智负担,可维护性等因素综合考虑,虚拟 dom 还是不错的选择。

vue react 应该都有 batch 操作,先攒够一堆,然后在更新上去

仿佛在逗我,虚拟 dom 性能永远超不过真实 DOM

页面上元素少的时候,直接用 DOM 确实有性能优势。比如说写自己博客,直接用 DOM 没什么问题,可以很细粒度的控制状态转移。
页面上有成百上千个元素的时候,你手算最优状态转移是不可能的。所以你直接操作 DOM 完成的不是最优状态转移,但是 vDOM 算出来的是最优状态转移,而 js 计算的开销比 DOM 操作小很多,这时候 vDOM 就有性能优势。

如果你能精确的明白你哪些 dom 操作会触发重绘,所以能够合并这些操作,那肯定是有性能优势的

问题是没人能做得到

状态数的增长也会导致你手算最优状态转移的难度暴增。三个状态互相转换你只需要写 3!=6 个 DOM 状态转移函数(K3 完全图)。7 个状态互相转换需要写 7!=5040 个 DOM 状态转移函数(K7 完全图)。

vdom 并不能保证 100%优于直接操作 dom ,还是需要看 diff 算法开销,只能说是很大一部分场景下会更加高效。
另外还有就是工程化的因素在里面,更多的是更加便捷的开发效率,不会有人为了追求性能去手动去更新 dom 吧?

如果没有 VDOM ,要知道一个状态有没有改变,得去 DOM 上拿对应的属性再和最新的状态比对,但 DOM 的读实在太慢了

imgtu.com/i/LrJBee

这个问题需要区分场景。
1 、dom 更新频率低:比如静态页面、广告页面,没有数据更新,一次性渲染。操作真实 DOM 性能优于 VDOM 。
2 、dom 更新频率高:有较强的交互性,数据更新频率高。操作真实 DOM 性能劣于 VDOM 。

vdom 应该更多的是提供了跨平台的可编程能力,如果仅仅只有直接去操作 DOM 这一种途径,那在非浏览器场景下就不可用,比如服务器端渲染,有 vdom 在其他平台上框架操作的也是 vdom ,只需要实现如何渲染 vdom 就好了。

忘了在哪篇 React 官方的文章看到的了,反正就是说“VDOM 是一个错误的说法,它令别人感觉是 DOM”,不知道有没有记错,这一点也在上面的一些回复也得到体现。

React 更新 DOM 其实也是你这种方法来更新,不然还能怎样用 JS 去更新 DOM 。

举个例子,面对 100 层深度的 DOM ,第 50 层和 99 层要同时被更新,你会怎样做。document.getElementById("root").innerHTML = '<div>.........</div>'吗? React 的话会直接找到需要更新的节点并进行替换。

github.com/solidjs/solid
欢迎你

使用 vdom 还有一个 [我认为最有潜力的] 因素是建立了抽象, 前端不再局限于浏览器, 可以拓展到其他载体的可视化中工程中.

这个可以啊!省去中间商赚差价!解决了楼上各位朋友提到的大规模更新的问题,还直接更新 DOM 。

楼主应该没做过 jquery 时代(以及之前)的前端开发吧

这个确实如此,RN 的跨平台不正是因为这个 VDOM 吗

这是发展时期某些粉丝发表的谬论,vdom 相比直接操作 dom 多了建立 vdom 与 diff 的过程,实践中评论来说 vdom 性能是比不过直接操作 dom 的

一次操作肯定直接操作 dom 快啊。vdom 最后也是操作 dom 啊。但是程序怎么可能只操作一次 dom 呢?是成百上千次操作,经过 vdom 整合,性能优势就出来了。

你这个举例明显不对啊。。。你的这个例子只有更新 DOM ,没有 DIFF 啊。

举例对比应该举 DIFF 的过程,而不是最后更新 DOM 的操作吧?就算事 VDOM ,最后也是这样更新 DOM 的。

其实直接操作 dom 消耗的性能在绝大部分业务系统中都毫无影响,重要的是 react\vue 这种 mvvm 模式带来了全新的开发模式,什么虚拟 dom 啊这类知识点让前端变的“难”了起来,要知道简单的东西都是让人不屑一顾的,要想测底站住脚必须要“难”

其实 dom 修改只是一方面,如果是 jq 时代过来的前端,会明显发现一个问题,dom 和数据是不一致的。
我记得 react vue 刚出来的时候宣传的点都会说到这个问题。
其中尤其是 vue 刚出来的时候双向绑定带来的便捷感,把传统的 jq 开发模式碾压的死死的。
打通 dom 和 数据 的同步之后的前端,才真正的有可能大规模的往工程化方向上去靠。
至于 dom 修改的性能提升 balabala ,其实私以为只是一个便利顺带的好处罢了

react 用 vdom 的原因是 render 函数要每次渲染都跑一次,不用 vdom 总不能每次都创造一次 dom 元素吧
而为啥要跑很多次 render 函数这就纯粹是抽象起来方便的因素了——简单说就是代码容易编写,因为每次运行 render 都是创建新的 vdom 树,类似于即时模式渲染的 gui
可以做到跟踪 dom 元素的话,那当然是这样快,但是这不方便抽象——Svelte 就需要造编译器以支持抽象
不方便抽象的后果要么是直接放弃,然后为了精细操作,代码就变得冗长且不易维护
或者就是强行抽象然后每次都重建整个 dom 树(比如直接重建整个列表的所有元素)——这种情况下,那当然就慢于 react 的 vdom 方案了
提示:
改 innerHTML 问题很大(即使只改文本),除非只在创建时用,不然看着 fps 爆炸吧)
要改就改 nodeValue (注意选择到文本节点而不是元素节点)

实际场景是 document.getElementById("app").innerHTML = "。。。。一万个元素。。。。。"!!
这时候就体现出虚拟 dom 的好处的,它可以在 js 的内存中直接判断过滤掉不需要更新的,这时候就变成了
document.getElementById("app").innerHTML = "。。。。几个元素。。。。。"
document.getElementById("app").innerHTML = "。。。。几个元素。。。。。"

自己实现一遍 react 就懂了, 如果没有虚拟 dom, 每次状态修改都要重新加载下面的所有组件, 因为我不知道这个 status 是哪些组件的 porps.
在你的例子里, 假如我有个表格, 数据在 table 的 status 里, 如果没有 vdom, 那么每次数据变化都要重新渲染表格, 但是 vdom 只需要找到被改过的 cell 就行了

而且如果没有 vdom 那么每次 setstatus 都要重新渲染, 而 vdom 可以把多次渲染合并为一次

这个要按复杂情况来, 当页面渲染数据很复杂或多的时候, 古早时期的方法是模板渲染然后直接替换, 整个替换,性能可想而知, 即使不用框架,最后还是会被动查出一个与之功能相似的 diff 算法

简单粗暴的“innerHTML=”看似便捷,不但有注入安全问题,而且还把里面绑定的事件、状态、属性全干掉了。
这时候你还得一个一个全部重新绑定、设置状态、设置属性。

你都 innerHTML 了。还操作 dom 干嘛。直接每次更改 reload 页面算求了

React 提这个是有它自己的语境在的。在官方文档中——它甚至有中文——描述了这一设计的动机:
zh-hans.reactjs.org/docs/faq-internals.html
zh-hans.reactjs.org/docs/reconciliation.html

直接操作 DOM 是最快的,可以去看下 SoldJS 这种没用虚拟 DOM 的库和 React 的性能对比。