DOM vs Virtual DOM

931 阅读5分钟

DOM 和 Virtual DOM 分别是什么?它们之间的区别是什么?各自有什么优缺点?

我们一定需要Virtual DOM吗? React中是怎么做的?

是什么?

DOM(Document Object Modle):文档对象模型,本质是对 结构化文本 的一种抽象,在页面渲染出的每一个结点都是一个真实DOM结构。

Virtual DOM: 以 JavaScript 对象形式存在的对 DOM 的描述,是对 HTML DOM 的一种抽象。

有什么区别

DOMVirtual DOM
操作时会引起页面的排版和重绘不会引起页面的排版和重绘
总损耗真实DOM完全增删改 + 排版与重绘(较多节点)虚拟DOM增删改 + (与Diff算法效率有关)真实DOM差异增删 + 排版和重绘(仅更新必要部分)

当使用 Virtual DOM 时,我们往往是频繁操作 Virtual DOM。然后一次性比较 真实DOM 和 Virtual DOM 之间的差异,并修改更新差异的部分到真实DOM (仅修改变更的真实DOM 节点)。

传统的原生apijQuery去操作DOM时,浏览器会从构建DOM树开始从头到尾执行一遍流程。

当你在一次操作时,需要更新10个DOM节点,浏览器没这么智能,收到第一个更新DOM请求后,并不知道后续还有9次更新操作,因此会马上执行流程,最终执行10次流程。

而通过 Viratula DOM,同样更新10个DOM节点,Virtual DOM 不会直接操作 DOM,而是将这10次更新的diff内容保存到本地的一个js对象中,最终将这个js对象一次性attachDOM树上,避免大量的无谓计算。

优缺点?

DOMVirtual DOM
优点所见即所得的使用(1)高性能:使用Virtual DOM,能够有效避免真实DOM数频繁更新,减少多次引起重绘与回流,提高性能 (2)跨平台:React借助虚拟DOM, 带来了跨平台的能力,一套代码多端运行
缺点(1)效率低:解析速度慢,内存占用过高 (2) 性能差:频繁操作真实DOM,易于导致重绘与回流(1) 在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化 (2) 首次渲染大量DOM时,由于多了一层虚拟DOM的计算,速度比正常稍慢

React中是怎么实现的Virtual DOM?

在 React 中有一个特性被成为JSX(一种预发糖),它是js语法的一种扩展。

Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用。

下面两种写法完全等价

const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);
const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

React 中提供 React.render 方法 用于将你创建好虚拟DOM节点插入到某个真实节点上,并渲染到页面上(例子如下)

const element = <h1>Hello World</h1> 
const root = document.getElementById('root') 
ReactDOM.render(vDom, root)
总结:
​
1. React中提供一种语法糖JSX。 JSX`通过`babel 的方式转成`React.createElement`执行。
1. React.createElement 的返回值是一个对象,也就是虚拟DOM

一定需要Virtual DOM 吗?

Virtual DOM 真的渲染快?真的性能好吗?答案是不一定。

理智告诉我们,快慢好坏的评价往往取决于参照物。这个世界没有免费的午餐,diff的计算并不是没有开销的。

以上面<h1> 元素中的 "Hello world" 更名为 "Hello everybody"为例。

使用Virtual Dom 的变更步骤至少需要

  • 检测节点,新旧VDOM中都是 <h1> 元素,保留相同的DOM节点
  • 枚举新旧VDOM 上的所有属性,一一比较差异,检查是否需要增删改
  • 将检测的变动属性更新到真实DOM 上

如果你直接精确的操作DOM,会节省前面的比较步骤,精准执行第三步。由此可见,精准操作DOM本身的性能一定是优于Virtual DOM的实现的。VDOM 在真实变更之前,还需要消耗内存计算Diff。

那么问题来了,为什么很多前端框架还是使用Virtual DOM?

理解虚拟DOM不是一个特性很重要。它是达到 声明性的、状态驱动的UI开发 的一种手段。

精准操作DOM的性能确实优于VDOM,但是精准操作本身与程序员的水平本身息息相关,我们很难保证团队内的每个成员水平都保持在高水平。所有的编码都能优化到对最小成本的操作真实DOM。

虚拟DOM很有价值,因为它允许您构建应用程序,而无需考虑状态转换,性能通常足够好,这样开发者在操作DOM更新的时候心智负担就会很小。这意味着更少的错误代码,进而在整体程序上提高性能和渲染效率。

除此之外,VDOM 因为是对DOM的抽象,天然就具有跨端的能力。

但事实证明,我们也可以在不使用虚拟DOM的情况下实现类似的编程模型。

总结

  1. 不需要将Virtual DOM 作为一个特性,它只是一种达到数据驱动UI开发的一种手段。它是对DOM的抽象描述,提供了统一管理DOM的能力,开发者不再需要记住复杂的DOM操作,不需要关心数据变动之后的更新,也不再要求每个开发者都能做到最优操作DOM,进而提升项目整体的性能和渲染效率
  2. 上来就说过,Virtual DOM 是对 DOM 的一种描述,本质是 javascript 对象,或者编译为其它语言的对象,那么换一种宿主环境,就可以让 vdom 在新的平台继续使用,比如去进行 SSR(Server Side Render) ,或者很出名的 React Native

参考文献

Virtual DOM is pure overhead