React、Vue 关于虚拟 DOM 的文章经常有这样的表述:因为直接操作真实 DOM 耗性能。妥否?

2022-04-20 11:32:40 +08:00
 Steel

学习 React 过程中,发现很多文章说到: 为什么要用 VDOM ,而不是直接操作真实 DOM ?都有类似这样的表述:直接操作真实 DOM 耗性能,细小的改动都可能导致重绘或重排。

但是如下这样直接操作 DOM ,不比用 VDOM 然后 Diff 后更新 DOM 性能更好吗?

document.getElementById("divId").innerHTML = "update text";

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

4022 次点击
所在节点    React
34 条回复
mxT52CRuqR6o5
2022-04-20 13:50:43 +08:00
这是发展时期某些粉丝发表的谬论,vdom 相比直接操作 dom 多了建立 vdom 与 diff 的过程,实践中评论来说 vdom 性能是比不过直接操作 dom 的
yaphets666
2022-04-20 14:04:20 +08:00
一次操作肯定直接操作 dom 快啊。vdom 最后也是操作 dom 啊。但是程序怎么可能只操作一次 dom 呢?是成百上千次操作,经过 vdom 整合,性能优势就出来了。
lscho
2022-04-20 14:06:23 +08:00
你这个举例明显不对啊。。。你的这个例子只有更新 DOM ,没有 DIFF 啊。

举例对比应该举 DIFF 的过程,而不是最后更新 DOM 的操作吧?就算事 VDOM ,最后也是这样更新 DOM 的。
dudubaba
2022-04-20 14:16:08 +08:00
其实直接操作 dom 消耗的性能在绝大部分业务系统中都毫无影响,重要的是 react\vue 这种 mvvm 模式带来了全新的开发模式,什么虚拟 dom 啊这类知识点让前端变的“难”了起来,要知道简单的东西都是让人不屑一顾的,要想测底站住脚必须要“难”
qzsi001
2022-04-20 14:17:26 +08:00
其实 dom 修改只是一方面,如果是 jq 时代过来的前端,会明显发现一个问题,dom 和数据是不一致的。
我记得 react vue 刚出来的时候宣传的点都会说到这个问题。
其中尤其是 vue 刚出来的时候双向绑定带来的便捷感,把传统的 jq 开发模式碾压的死死的。
打通 dom 和 数据 的同步之后的前端,才真正的有可能大规模的往工程化方向上去靠。
至于 dom 修改的性能提升 balabala ,其实私以为只是一个便利顺带的好处罢了
codehz
2022-04-20 14:22:38 +08:00
react 用 vdom 的原因是 render 函数要每次渲染都跑一次,不用 vdom 总不能每次都创造一次 dom 元素吧
而为啥要跑很多次 render 函数这就纯粹是抽象起来方便的因素了——简单说就是代码容易编写,因为每次运行 render 都是创建新的 vdom 树,类似于即时模式渲染的 gui
可以做到跟踪 dom 元素的话,那当然是这样快,但是这不方便抽象——Svelte 就需要造编译器以支持抽象
不方便抽象的后果要么是直接放弃,然后为了精细操作,代码就变得冗长且不易维护
或者就是强行抽象然后每次都重建整个 dom 树(比如直接重建整个列表的所有元素)——这种情况下,那当然就慢于 react 的 vdom 方案了
提示:
改 innerHTML 问题很大(即使只改文本),除非只在创建时用,不然看着 fps 爆炸吧)
要改就改 nodeValue (注意选择到文本节点而不是元素节点)
KouShuiYu
2022-04-20 16:21:53 +08:00
实际场景是 document.getElementById("app").innerHTML = "。。。。一万个元素。。。。。"!!
这时候就体现出虚拟 dom 的好处的,它可以在 js 的内存中直接判断过滤掉不需要更新的,这时候就变成了
document.getElementById("app").innerHTML = "。。。。几个元素。。。。。"
document.getElementById("app").innerHTML = "。。。。几个元素。。。。。"
aguesuka
2022-04-20 16:30:49 +08:00
自己实现一遍 react 就懂了, 如果没有虚拟 dom, 每次状态修改都要重新加载下面的所有组件, 因为我不知道这个 status 是哪些组件的 porps.

在你的例子里, 假如我有个表格, 数据在 table 的 status 里, 如果没有 vdom, 那么每次数据变化都要重新渲染表格, 但是 vdom 只需要找到被改过的 cell 就行了
aguesuka
2022-04-20 16:33:54 +08:00
而且如果没有 vdom 那么每次 setstatus 都要重新渲染, 而 vdom 可以把多次渲染合并为一次
retrocode
2022-04-20 16:36:00 +08:00
这个要按复杂情况来, 当页面渲染数据很复杂或多的时候, 古早时期的方法是模板渲染然后直接替换, 整个替换,性能可想而知, 即使不用框架,最后还是会被动查出一个与之功能相似的 diff 算法
DOLLOR
2022-04-20 17:01:18 +08:00
简单粗暴的“innerHTML=”看似便捷,不但有注入安全问题,而且还把里面绑定的事件、状态、属性全干掉了。
这时候你还得一个一个全部重新绑定、设置状态、设置属性。
huijiewei
2022-04-20 17:10:42 +08:00
你都 innerHTML 了。还操作 dom 干嘛。直接每次更改 reload 页面算求了
fayetitus
2022-04-20 17:57:35 +08:00
React 提这个是有它自己的语境在的。在官方文档中——它甚至有中文——描述了这一设计的动机:
https://zh-hans.reactjs.org/docs/faq-internals.html
https://zh-hans.reactjs.org/docs/reconciliation.html
ebushicao
2022-04-20 18:19:41 +08:00
直接操作 DOM 是最快的,可以去看下 SoldJS 这种没用虚拟 DOM 的库和 React 的性能对比。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/848093

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX