我看了一个React开发者的演讲(Pete Hunt: React: Rethinking best practices -- JSConf EU 2013),其中演讲者提到模型的脏检查可能会很慢。但是,计算虚拟DOM之间的差异实际上是否更少效率,因为在大多数情况下,虚拟DOM应该比模型更大?
我非常喜欢虚拟DOM的潜力(特别是服务器端渲染),但我想知道所有的优缺点。
我看了一个React开发者的演讲(Pete Hunt: React: Rethinking best practices -- JSConf EU 2013),其中演讲者提到模型的脏检查可能会很慢。但是,计算虚拟DOM之间的差异实际上是否更少效率,因为在大多数情况下,虚拟DOM应该比模型更大?
我非常喜欢虚拟DOM的潜力(特别是服务器端渲染),但我想知道所有的优缺点。
我是virtual-dom模块的主要作者,所以也许可以回答你的问题。实际上有两个需要解决的问题:
在React中,每个组件都有一个状态。这个状态就像你可能在knockout或其他MVVM样式库中找到的可观察对象一样。基本上,React知道何时重新渲染场景,因为它能够观察到这些数据何时发生了变化。脏检查比观察对象慢,因为您必须定期轮询数据并递归检查数据结构中的所有值。相比之下,设置状态上的值将向侦听器发出信号,表示某些状态已更改,因此React可以简单地侦听状态上的更改事件并排队重新渲染。
虚拟DOM用于DOM的高效重新渲染。这与检查数据的脏不相关。您可以使用虚拟DOM进行重新渲染,无论是否进行脏检查。在计算两个虚拟树之间的差异方面确实存在一些开销,但虚拟DOM差异是关于理解DOM中需要更新的内容,而不是您的数据是否已更改。事实上,差异算法本身就是一个脏检查器,但它用于检查DOM是否是脏的。
我们的目标是仅在状态更改时重新呈现虚拟树。因此,使用可观察对象来检查状态是否更改是防止不必要的重新渲染的有效方法,这将导致许多不必要的树差异。如果没有任何更改,我们就什么也不做。
虚拟DOM非常好,因为它让我们的代码看起来像是在重新渲染整个场景。在后台,我们想要计算一个补丁操作,以便更新DOM并使其看起来符合我们的期望。因此,尽管虚拟DOM的差异/补丁算法可能不是最优解决方案,但它为我们提供了一种非常好的方式来表达我们的应用程序。我们只需声明确切地想要什么,React/virtual-dom 将会找出如何使您的场景看起来像这样。我们不必手动进行DOM操作或混淆之前的DOM状态。我们也不必重新渲染整个场景,这可能比修补它更低效。
我最近阅读了一篇关于React的差异算法的详细文章,链接在这里:http://calendar.perfplanet.com/2013/diff/。从我的理解来看,React之所以快速是因为:
与脏检查相比,我认为主要的区别有:
模型脏检查:每当调用setState
时,React组件都会被明确地设置为脏,所以这里不需要进行(数据)比较。而对于脏检查,(模型)比较始终会在每个循环周期内发生。
DOM更新:修改DOM也会应用和计算CSS样式、布局,因此DOM操作非常昂贵。无需修改DOM可节省的时间可能比虚拟DOM的差异计算所花费的时间更长。
对于具有大量字段或大型列表等复杂模型来说,第二点甚至更加重要。复杂模型的一个字段更改将导致仅涉及该字段的DOM元素的操作,而不是整个视图/模板。
$scope.$digest
在每个digest周期中会被执行多次,这意味着与单次部分虚拟DOM树比较相比,需要进行多次完整数据比较。 - tungd我非常喜欢虚拟DOM的潜力(尤其是服务器端渲染),但我想知道所有的优缺点。
-- 发帖者
React并不是唯一的DOM操作库。我鼓励你通过阅读这篇来自Auth0的文章(链接在此)来了解其他替代方案,其中包含详细的解释和基准测试。正如你所问的,我将在这里列出它们的优缺点:
React.js的虚拟DOM
优点
- 快速高效的"diffing"算法
- 多个前端(JSX,超文本标记语言)
- 足够轻便以在移动设备上运行
- 有很多关注和支持
- 可以在没有React的情况下使用(即作为独立引擎)
缺点
- 完整的内存DOM副本(内存使用较高)
- 没有区分静态和动态元素
Ember.js的Glimmer
优点
- 快速高效的diffing算法
- 区分静态和动态元素
- 与Ember的API完全兼容(即使不对现有代码进行重大更新也能获得好处)
- 轻量级内存中的DOM表示
缺点
- 仅适用于Ember
- 仅有一个前端可用
增量DOM
优点
- 减少内存使用
- 简单的API
- 易于与许多前端和框架集成(从一开始就是作为模板引擎后端而设计的)
缺点
- 不如其他库快(这是有争议的,请参见下面的基准测试结果)
- 使用较少,社区普及度较低
虚拟 DOM 不是由 React 发明的。它是 HTML DOM 的一部分。 它是轻量级的,与浏览器特定的实现细节分离。
我们可以将虚拟 DOM 视为 React 对 HTML DOM 的本地和简化副本。它允许 React 在这个抽象世界中进行计算,并跳过“真实”的 DOM 操作,通常是缓慢和浏览器特定的。实际上,DOM 和虚拟 DOM 之间没有太大的区别。
以下是使用虚拟 DOM 的原因(来源 ReactJS 中的虚拟 DOM):
当你执行以下代码时:document.getElementById('elementId').innerHTML = "New Value"
以下事情会发生:
除了更新DOM属性,即值。它遵循一种算法。
现在,假设您直接更新DOM 10次,那么所有上述步骤都将依次运行,并且更新DOM算法将花费时间来更新DOM值。
这就是为什么真实DOM比虚拟DOM慢的原因。