我在(Pete Hunt: React: Rethinking best practice -- JSConf EU 2013 )上看到了一个React开发者演讲,演讲者提到模型的脏检查可能很慢。但是,在大多数情况下,虚拟 DOM 应该比模型大,因此计算虚拟 DOM 之间的差异实际上不是性能更差吗?
我真的很喜欢 Virtual DOM 的潜在力量(尤其是服务器端渲染),但我想知道所有的优点和缺点。
我在(Pete Hunt: React: Rethinking best practice -- JSConf EU 2013 )上看到了一个React开发者演讲,演讲者提到模型的脏检查可能很慢。但是,在大多数情况下,虚拟 DOM 应该比模型大,因此计算虚拟 DOM 之间的差异实际上不是性能更差吗?
我真的很喜欢 Virtual DOM 的潜在力量(尤其是服务器端渲染),但我想知道所有的优点和缺点。
I'm the primary author of a virtual-dom module, so I might be able to answer your questions. There are in fact 2 problems that need to be solved here
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.
We aim to re-render the virtual tree only when the state changes. So using an observable to check if the state has changed is an efficient way to prevent unnecessary re-renders, which would cause lots of unnecessary tree diffs. If nothing has changed, we do nothing.
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.
我最近在这里阅读了一篇关于 React diff 算法的详细文章:http: //calendar.perfplanet.com/2013/diff/。据我了解,让 React 快速的原因是:
与脏检查相比,IMO 的主要区别在于:
模型脏检查:React 组件在setState
被调用时被显式设置为脏,因此这里不需要比较(数据)。对于脏检查,(模型的)比较总是在每个摘要循环中发生。
DOM 更新:DOM 操作非常昂贵,因为修改 DOM 也会应用和计算 CSS 样式、布局。从不必要的 DOM 修改中节省的时间可能比区分虚拟 DOM 所花费的时间更长。
第二点对于非平凡模型(例如具有大量字段或列表的模型)更为重要。复杂模型的一个字段更改将只导致涉及该字段的 DOM 元素所需的操作,而不是整个视图/模板。
我真的很喜欢 Virtual DOM 的潜在力量(尤其是服务器端渲染),但我想知道所有的优点和缺点。
-- 欧普
React 不是唯一的 DOM 操作库。我鼓励您通过阅读来自 Auth0 的这篇文章来了解替代方案,其中包括详细的解释和基准。正如你所问的,我将在这里强调它们的优缺点:
React.js 的虚拟 DOM
优点
- 快速高效的“差异化”算法
- 多个前端(JSX、超脚本)
- 足够轻巧,可以在移动设备上运行
- 很多牵引力和思想分享
- 可以在没有 React 的情况下使用(即作为独立引擎)
缺点
- DOM 的完整内存副本(更高的内存使用)
- 静态和动态元素之间没有区别
Ember.js 的微光
优点
- 快速高效的差分算法
- 静态元素和动态元素的区别
- 100% 与 Ember 的 API 兼容(无需对现有代码进行重大更新即可获得好处)
- DOM 的轻量级内存表示
缺点
- 仅用于 Ember
- 只有一个前端可用
增量 DOM
优点
- 减少内存使用
- 简单的 API
- 轻松与许多前端和框架集成(从一开始就作为模板引擎后端)
缺点
- 不如其他库快(这是有争议的,请参阅下面的基准)
- 更少的思想分享和社区使用
以下是 React 团队成员 Sebastian Markbåge 的评论,它提供了一些启示:
React 对输出进行区分(这是一种已知的可序列化格式,DOM 属性)。这意味着源数据可以是任何格式。它可以是不可变的数据结构和闭包内部的状态。
Angular 模型不保留引用透明度,因此本质上是可变的。您改变现有模型以跟踪更改。如果您的数据源每次都是不可变数据或新数据结构(例如 JSON 响应)怎么办?
脏检查和 Object.observe 不适用于闭包范围状态。
这两件事显然非常限制功能模式。
此外,当您的模型复杂性增加时,进行脏跟踪变得越来越昂贵。然而,如果你只在可视化树上进行差异化,比如 React,那么它就不会增长太多,因为你能够在任何给定点在屏幕上显示的数据量都受到 UI 的限制。皮特上面的链接涵盖了更多的性能优势。
Virtual Dom 不是由 react 发明的。它是 HTML dom 的一部分。它是轻量级的,并且与特定于浏览器的实现细节分离。
我们可以将虚拟 DOM 视为 React 的 HTML DOM 的本地和简化副本。它允许 React 在这个抽象世界中进行计算并跳过“真实”的 DOM 操作,这些操作通常很慢且特定于浏览器。实际上 DOM 和 VIRTUAL DOM 并没有太大的区别。
以下是使用 Virtual Dom 的要点(ReactJS 中的源 Virtual DOM):
当你这样做时:
document.getElementById('elementId').innerHTML = "New Value" Following thing happens:
- 浏览器需要解析 HTML
- 它删除 elementId 的子元素
- 用新值更新 DOM 值
- 重新计算父子的css
- 更新布局,即每个元素在屏幕上的精确坐标
- 遍历渲染树并在浏览器显示上绘制
重新计算 CSS 和更改的布局使用复杂的算法,它们会影响性能。
以及更新 DOM 属性,即。价值观。它遵循一个算法。
现在,假设如果你直接更新 DOM 10 次,那么上面所有的步骤都会一个一个地运行,更新 DOM 算法需要时间来更新 DOM 值。
这就是为什么 Real DOM 比 virtual DOM 慢的原因。