我在(Pete Hunt:React:Rethinking Best Practices-JSConf EU 2013)上看到了一个React开发人员的演讲,演讲者提到对模型进行脏检查可能很慢。但是,由于虚拟DOM在大多数情况下应该比模型更大,难道计算虚拟DOM之间的差异实际上还没有表现得更好吗?
我真的很喜欢Virtual DOM(尤其是服务器端渲染)的潜在功能,但是我想知道所有的优点和缺点。
我在(Pete Hunt:React:Rethinking Best Practices-JSConf EU 2013)上看到了一个React开发人员的演讲,演讲者提到对模型进行脏检查可能很慢。但是,由于虚拟DOM在大多数情况下应该比模型更大,难道计算虚拟DOM之间的差异实际上还没有表现得更好吗?
我真的很喜欢Virtual DOM(尤其是服务器端渲染)的潜在功能,但是我想知道所有的优点和缺点。
Answers:
我是virtual-dom模块的主要作者,因此我也许可以回答您的问题。实际上这里有两个问题需要解决
在React中,每个组件都有一个状态。这种状态就像您可以在敲除或其他MVVM样式库中发现的那样。本质上,React知道何时重新渲染场景,因为它能够观察到这些数据何时更改。脏检查比可观察到的检查要慢,因为必须定期轮询数据并递归检查数据结构中的所有值。相比之下,在状态上设置一个值将向侦听器发出某些状态已更改的信号,因此React可以简单地侦听状态上的更改事件并排队重新渲染。
虚拟DOM用于有效地重新渲染DOM。这实际上与对数据进行脏检查无关。您可以使用带有或不带有脏检查的虚拟DOM重新渲染。没错,在计算两个虚拟树之间的差异时会产生一些开销,但是虚拟DOM差异是关于了解DOM中需要更新的内容,而不是了解您的数据是否已更改。实际上,diff算法本身就是一个脏检查器,但是它用于查看DOM是否脏了。
我们旨在仅在状态更改时才重新渲染虚拟树。因此,使用可观察对象来检查状态是否已更改是防止不必要的重新渲染的有效方法,因为重新渲染会导致大量不必要的树差异。如果什么都没有改变,我们什么也不做。
虚拟DOM很好,因为它使我们可以像重新渲染整个场景一样编写代码。在幕后,我们要计算补丁操作,以更新DOM来查看我们的期望。因此,尽管虚拟DOM差异/补丁算法可能不是最佳解决方案,但它为我们提供了一种表达应用程序的好方法。我们只声明了我们想要的东西,React / virtual-dom将确定如何使您的场景看起来像这样。我们不必手动进行DOM操作,也不必对以前的DOM状态感到困惑。我们也不必重新渲染整个场景,这可能比修补它的效率低得多。
unnecessary re-renders
什么?
this.state.cats = 99
,则仍然需要进行脏检查以检查模型更改,就像Angular脏检查$ scope树一样。这不是两种技术速度的比较,只是陈述React不会进行脏检查,因为它具有Backbone样式设置器。
我最近在这里阅读了有关React差异算法的详细文章:http : //calendar.perfplanet.com/2013/diff/。据我了解,使React快速的原因是:
与脏检查相比,IMO的主要区别在于:
模型脏检查:每次setState
调用时,React组件都被显式设置为脏,因此这里不需要(数据)比较。对于脏检查,(模型的)比较总是在每个摘要循环中进行。
DOM更新:DOM操作非常昂贵,因为修改DOM还将应用并计算CSS样式,布局。不必要的DOM修改所节省的时间可能比扩散虚拟DOM所花费的时间更长。
对于非平凡的模型(例如具有大量字段或大量列表的模型),第二点更为重要。复杂模型的一个字段更改将仅导致涉及该字段的DOM元素所需的操作,而不是整个视图/模板。
$scope.$digest
,因此每个摘要周期要执行多次,因此它是完整数据比较的多次与部分虚拟DOM树比较的一次。
我真的很喜欢Virtual DOM(尤其是服务器端渲染)的潜在功能,但是我想知道所有的优点和缺点。
-OP
React并不是唯一的DOM操作库。我鼓励您通过阅读Auth0的这篇文章来了解替代方法,其中包括详细的说明和基准。根据您的要求,在这里我将重点介绍它们的优缺点:
React.js的虚拟DOM
优点
- 快速高效的“差异”算法
- 多个前端(JSX,超标)
- 轻巧到足以在移动设备上运行
- 很多牵引力和思想分享
- 无需React也可以使用(即作为独立引擎)
缺点
- DOM的完整内存副本(更高的内存使用量)
- 静态和动态元素之间没有区别
Ember.js的微光
优点
- 快速高效的差分算法
- 静态和动态元素之间的区别
- 100%与Ember的API兼容(无需大量更新现有代码即可获得收益)
- DOM的轻量级内存表示
缺点
- 只能在Ember中使用
- 仅一个前端可用
增量DOM
优点
- 减少内存使用
- 简单的API
- 轻松集成许多前端和框架(从一开始就希望作为模板引擎后端)
缺点
- 不如其他库快(这是有争议的,请参见下面的基准测试)
- 更少的思想分享和社区使用
这是React团队成员SebastianMarkbåge的评论,阐明了一些观点:
React对输出进行区分(这是已知的可序列化格式,DOM属性)。这意味着源数据可以是任何格式。它可以是不可变的数据结构,也可以是闭包内部的状态。
Angular模型不会保留参照透明性,因此本质上是可变的。您对现有模型进行变异以跟踪更改。如果您的数据源每次都是不可变数据或新的数据结构(例如JSON响应)怎么办?
脏检查和Object.observe不适用于关闭范围状态。
显然,这两件事非常限制了功能模式。
此外,当模型复杂度增加时,进行脏跟踪变得越来越昂贵。但是,如果仅像在React之类的视觉树上进行比较,则它不会增长太多,因为您可以在任何给定点显示在屏幕上的数据量受到UI的限制。皮特(Pete)的上面的链接涵盖了更多的性能好处。
Virtual Dom不是通过react发明的。它是HTML dom的一部分。它是轻量级的,并且与浏览器特定的实现细节分离。
我们可以将虚拟DOM视为React的HTML DOM的本地和简化副本。它允许React在这个抽象的世界中进行计算,并跳过“真实的” DOM操作,这些操作通常很慢且特定于浏览器。实际上,DOM和虚拟DOM之间并没有很大的区别。
以下是使用虚拟Dom的要点(ReactJS中的源虚拟DOM):
当您这样做时:
document.getElementById('elementId').innerHTML = "New Value" Following thing happens:
- 浏览器需要解析HTML
- 删除elementId的子元素
- 用新值更新DOM值
- 重新计算父母和孩子的CSS
- 更新布局,即每个元素在屏幕上的精确坐标
- 遍历渲染树并将其绘制在浏览器显示屏上
重新计算CSS和更改的布局使用复杂的算法,它们会影响性能。
以及更新DOM属性。价值观。它遵循一种算法。
现在,假设您直接更新DOM 10次,那么以上所有步骤将一个接一个地运行,并且更新DOM算法将花费一些时间来更新DOM值。
这就是为什么Real DOM比虚拟DOM慢的原因。