我看过一个React开发的演讲(Pete Hunt: React: Rethinking best practices—JSConf EU 2013),演讲者提到模型的脏检查可能会很慢。但是,在大多数情况下,虚拟DOM应该比模型更大,因此计算虚拟DOM之间的差异实际上不是性能更差吗?

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


当前回答

In React, each of your components have a state. This state is like an observable you might find in knockout or other MVVM style libraries. Essentially, React knows when to re-render the scene because it is able to observe when this data changes. Dirty checking is slower than observables because you must poll the data at a regular interval and check all of the values in the data structure recursively. By comparison, setting a value on the state will signal to a listener that some state has changed, so React can simply listen for change events on the state and queue up re-rendering.The virtual DOM is used for efficient re-rendering of the DOM. This isn't really related to dirty checking your data. You could re-render using a virtual DOM with or without dirty checking. You're right in that there is some overhead in computing the diff between two virtual trees, but the virtual DOM diff is about understanding what needs updating in the DOM and not whether or not your data has changed. In fact, the diff algorithm is a dirty checker itself but it is used to see if the DOM is dirty instead.

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

其他回答

我最近在这里读了一篇关于React的diff算法的详细文章:http://calendar.perfplanet.com/2013/diff/。根据我的理解,React快速的原因是:

批处理DOM读写操作。 高效更新子树。

与脏检查相比,IMO的主要区别是:

模型脏检查:无论何时调用setState, React组件都显式地设置为脏,因此这里不需要(数据)比较。对于脏检查,(模型的)比较总是发生在每个摘要循环中。 DOM更新:DOM操作非常昂贵,因为修改DOM也会应用和计算CSS样式和布局。从不必要的DOM修改中节省的时间可能比区别虚拟DOM所花费的时间要长。

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

下面是React团队成员Sebastian Markbåge的一篇评论,它揭示了一些问题:

React does the diffing on the output (which is a known serializable format, DOM attributes). This means that the source data can be of any format. It can be immutable data structures and state inside of closures. The Angular model doesn't preserve referential transparency and therefore is inherently mutable. You mutate the existing model to track changes. What if your data source is immutable data or a new data structure every time (such as a JSON response)? Dirty checking and Object.observe does not work on closure scope state. These two things are very limiting to functional patterns obviously. Additionally, when your model complexity grows, it becomes increasingly expensive to do dirty tracking. However, if you only do diffing on the visual tree, like React, then it doesn't grow as much since the amount of data you're able to show on the screen at any given point is limited by UIs. Pete's link above covers more of the perf benefits.

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

我是一个虚拟dom模块的主要作者,所以我可能能够回答你的问题。事实上,这里有两个问题需要解决

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

In React, each of your components have a state. This state is like an observable you might find in knockout or other MVVM style libraries. Essentially, React knows when to re-render the scene because it is able to observe when this data changes. Dirty checking is slower than observables because you must poll the data at a regular interval and check all of the values in the data structure recursively. By comparison, setting a value on the state will signal to a listener that some state has changed, so React can simply listen for change events on the state and queue up re-rendering.

The virtual DOM is used for efficient re-rendering of the DOM. This isn't really related to dirty checking your data. You could re-render using a virtual DOM with or without dirty checking. You're right in that there is some overhead in computing the diff between two virtual trees, but the virtual DOM diff is about understanding what needs updating in the DOM and not whether or not your data has changed. In fact, the diff algorithm is a dirty checker itself but it is used to see if the DOM is dirty instead.

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

A virtual DOM is nice because it lets us write our code as if we were re-rendering the entire scene. Behind the scenes we want to compute a patch operation that updates the DOM to look how we expect. So while the virtual DOM diff/patch algorithm is probably not the optimal solution, it gives us a very nice way to express our applications. We just declare exactly what we want and React/virtual-dom will work out how to make your scene look like this. We don't have to do manual DOM manipulation or get confused about previous DOM state. We don't have to re-render the entire scene either, which could be much less efficient than patching it.

我真的很喜欢Virtual DOM的潜在功能(特别是 服务器端渲染),但我想知道所有的优点和缺点。 ——凤凰社

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

React.js' Virtual DOM PROS Fast and efficient "diffing" algorithm Multiple frontends (JSX, hyperscript) Lightweight enough to run on mobile devices Lots of traction and mindshare Can be used without React (i.e. as an independent engine) CONS Full in-memory copy of the DOM (higher memory use) No differentiation between static and dynamic elements Ember.js' Glimmer PROS Fast and efficient diffing algorithm Differentiation between static and dynamic elements 100% compatible with Ember's API (you get the benefits without major updates to your existing code) Lightweight in-memory representation of the DOM CONS Meant to be used only in Ember Only one frontend available Incremental DOM PROS Reduced memory usage Simple API Easily integrates with many frontends and frameworks (meant as a template engine backend from the beginning) CONS Not as fast as other libraries (this is arguable, see the benchmarks below) Less mindshare and community use

虚拟Dom不是react发明的。它是HTML dom的一部分。 它是轻量级的,并且脱离了特定于浏览器的实现细节。

我们可以把虚拟DOM看作是React对HTML DOM的本地简化副本。它允许React在这个抽象的世界中进行计算,而跳过“真正的”DOM操作,这些操作通常很慢,而且是特定于浏览器的。实际上,DOM和VIRTUAL DOM之间没有太大的区别。

下面是使用Virtual Dom的原因(ReactJS中的source Virtual Dom):

当你这样做时: . getelementbyid(“elementId”)。innerHTML = "New Value"会发生以下事情: 浏览器需要解析HTML 它删除了elementId的子元素 用新值更新DOM值 重新计算父节点和子节点的css 更新布局,即每个元素在屏幕上的精确坐标 遍历渲染树并在浏览器显示上绘制它 重新计算CSS和更改的布局使用复杂的算法和 它们影响表演。

以及更新DOM属性。值。它遵循一种算法。

现在,假设您直接更新DOM 10次,那么上述所有步骤将逐一运行,更新DOM算法将花费时间来更新DOM值。

这就是为什么真实DOM比虚拟DOM慢。