我看过一个React开发的演讲(Pete Hunt: React: Rethinking best practices—JSConf EU 2013),演讲者提到模型的脏检查可能会很慢。但是,在大多数情况下,虚拟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

其他回答

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