为什么说React的虚拟DOM概念比脏模型检查更高效?

我在http://www.youtube.com/watch?v=x7cQ3mrcKaY上看到了一个React开发人员的演讲,演讲者提到模型的肮脏检查可能会很慢。 但是,由于在大多数情况下,虚拟DOM应该比模型更大,所以不计算虚拟DOM之间的差异实际上甚至更less。

我真的很喜欢虚拟DOM的潜在力量(特别是服务器端渲染),但我想知道所有的优点和缺点。

我是虚拟DOM模块的主要作者,所以我可以回答你的问题。 其实有两个问题需要在这里解决

  1. 我什么时候重新渲染? 答:当我观察到数据很脏时。
  2. 我如何有效地重新渲染? 答:使用虚拟DOM来生成一个真正的DOM补丁

在React中,你的每个组件都有一个状态。 这个状态就像在knockout或其他MVVM风格的库中可以看到的那样。 本质上,React知道何时重新渲染场景,因为它能够观察这个数据何时改变。 脏检查比observables慢,因为您必须定期轮询数据并recursion检查数据结构中的所有值。 相比之下,在状态上设置一个值会告诉一个监听者一些状态已经改变,所以React可以简单地监听状态的变化事件并排队重新渲染。

虚拟DOM用于高效地重新呈现DOM。 这实际上并不涉及检查你的数据。 您可以使用虚拟DOM重新呈现,无论是否进行脏检查。 你是对的,在计算两个虚拟树之间的差异时有一些开销,但是虚拟DOM差异是关于理解DOM中需要更新的内容而不是你的数据是否已经改变。 实际上, diffalgorithm本身就是一个脏检查器,但是它用来查看DOM是否脏。

我们的目标是只在状态改变时重新渲染虚拟树。 因此,使用observable来检查状态是否已经改变是防止不必要的重新渲染的有效方法,这将导致大量不必要的树差异。 如果什么都没有改变,我们什么也不做。

一个虚拟的DOM是好的,因为它让我们编写我们的代码,就好像我们正在重新渲染整个场景一样。 在幕后,我们想要计算一个补丁操作,更新DOM来看看我们的期望。 所以,虽然虚拟DOM差异/补丁algorithm可能不是最佳解决scheme ,但它给了我们一个很好的方式来expression我们的应用程序。 我们只是声明我们想要的,React / virtual-dom将解决如何让你的场景看起来像这样。 我们不必手动操作DOM,或者对以前的DOM状态感到困惑。 我们不必重新渲染整个场景,这可能比修补效率低得多。

我最近在这里阅读了关于React的diffalgorithm的详细文章: http : //calendar.perfplanet.com/2013/diff/ 。 据我所知,使React快速的是:

  • 批量DOM读/写操作。
  • 只有高效的子树更新。

与肮脏检查相比,IMO的主要差异是:

  1. 模型脏检查 :每当setState被调用时,React组件被显式地设置为脏,所以这里不需要比较(数据)。 对于脏检查,比较(模型)总是发生在每个摘要循环中。

  2. DOM更新 :DOM操作非常昂贵,因为修改DOM也会应用和计算CSS样式,布局。 从不必要的DOM修改中节省的时间可以比花费在虚拟DOM上的时间更长。

第二点对于诸如具有大量字段或大列表的非平凡模型更为重要。 复杂模型的一个字段变化只会导致涉及该字段的DOM元素所需的操作,而不是整个视图/模板。

我真的很喜欢虚拟DOM的潜在力量(特别是服务器端渲染),但我想知道所有的优点和缺点。

– OP

React不是唯一的DOM操作库。 我鼓励您通过阅读Auth0中的这篇文章来了解其他方法,包括详细的解释和基准。 我会在这里强调他们的优点和缺点,正如你所问:

React.js的虚拟DOM

在这里输入图像描述

PROS

  • 快速高效的“差异化”algorithm
  • 多个前端(JSX,hyperscript)
  • 轻量级足以在移动设备上运行
  • 大量的牵引力和思想共享
  • 可以使用没有反应(即作为一个独立的引擎)

缺点

  • 完整的DOM内存拷贝(更高的内存使用)
  • 静态和dynamic元素没有区别

Ember.js'微光

在这里输入图像描述

PROS

  • 快速有效的差异化algorithm
  • 静态和dynamic元素的区分
  • 与Ember的API 100%兼容(您可以获得优势,而不必对现有代码进行重大更新)
  • DOM的轻量级内存中表示

缺点

  • 只能用于Ember
  • 只有一个前端可用

增量DOM

在这里输入图像描述

PROS

  • 减less内存使用量
  • 简单的API
  • 轻松地集成了许多前端和框架(从一开始就意味着作为模板引擎的后端)

缺点

  • 没有其他图书馆那么快(这是有争议的,见下面的基准)
  • 较less的思想和社区的使用

React团队成员SebastianMarkbåge对此发表了一些评论:

React在输出(这是一个已知的可序列化格式,DOM属性)上进行差异化。 这意味着源数据可以是任何格式。 它可以是不可变的数据结构和closures状态。

Angular模型不保留参考透明度,因此是固有的可变的。 你改变现有的模型来跟踪变化。 如果您的数据源每次都是不可变的数据或新的数据结构(比如JSON响应)呢?

脏检查和Object.observe不适用于闭包范围状态。

这两件事显然是function模式的限制。

另外,当你的模型复杂度增加时,做脏跟踪变得越来越昂贵。 但是,如果您只在可视化树上进行区分,例如React,那么它的增长速度并不会很快,因为在任何给定的点上,屏幕上显示的数据量都会受到UI的限制。 皮特上面的链接涵盖了更多的优势。

https://news.ycombinator.com/item?id=6937668

虚拟大教堂不是由反应发明的。 它是HTML DOM的一部分。 它是轻量级的,并从浏览器特定的实现细节中分离出来。

我们可以将虚拟DOM视为React的HTML DOM的本地和简化副本。 它允许React在这个抽象的世界中进行计算,并跳过“真正”的DOM操作,通常是缓慢的和特定于浏览器的。 其实DOM和虚拟DOM没有很大的区别。

以下是为什么使用Virtual Dom的要点:

当你这样做时:

 document.getElementById('elementId').innerHTML = "New Value" 

发生以下事情:

  1. 浏览器需要parsingHTML
  2. 它删除elementId的子元素
  3. 用新值更新DOM值
  4. 重新计算父母和孩子的CSS
  5. 更新布局,即每个元素在屏幕上的确切坐标
  6. 遍历渲染树并在浏览器上显示

重新计算CSS和更改布局使用复杂的algorithm,它们影响性能,以及更新DOM属性,即。 值。 它遵循一个algorithm。

现在,假设如果你直接更新DOM 10次,那么所有上述步骤将逐一运行,更新DOMalgorithm将需要时间来更新DOM值。

这就是为什么Real DOM比虚拟DOM慢的原因。