为什么说 React 的 Virtual DOM 概念比脏模型检查的性能更高?

IT技术 javascript dom reactjs virtual-dom
2021-01-20 13:16:16

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

我真的很喜欢 Virtual DOM(尤其是服务器端渲染)的潜在力量,但我想知道所有的优点和缺点。

5个回答

我是virtual-dommodule的主要作者,所以我可以回答你的问题。实际上这里有两个问题需要解决

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

在 React 中,你的每个组件都有一个状态。这种状态就像一个可以在淘汰赛或其他 MVVM 风格库中找到的可观察对象。本质上,React 知道何时重新渲染场景,因为它能够观察到这些数据何时发生变化。脏检查比 observable 慢,因为您必须定期轮询数据并递归检查数据结构中的所有值。相比之下,在状态上设置一个值将向侦听器发出信号,表明某些状态已更改,因此 React 可以简单地侦听状态上的更改事件并排队重新渲染。

虚拟 DOM 用于高效地重新渲染 DOM。这与脏检查您的数据并没有真正的关系。您可以使用带有或不带有脏检查的虚拟 DOM 重新渲染。你是对的,在计算两个虚拟树之间的差异时有一些开销,但虚拟 DOM 差异是关于了解 DOM 中需要更新的内容,而不是您的数据是否已更改。事实上,diff 算法本身就是一个脏检查器,但它用于查看 DOM 是否脏。

我们的目标是仅在状态改变时重新渲染虚拟树。因此,使用 observable 来检查状态是否已更改是防止不必要的重新渲染的有效方法,这会导致许多不必要的树差异。如果一切都没有改变,我们就什么都不做。

虚拟 DOM 很好,因为它让我们可以像重新渲染整个场景一样编写代码。在幕后,我们想要计算一个补丁操作来更新 DOM 以符合我们的预期。因此,虽然虚拟 DOM diff/patch 算法可能不是最佳解决方案,但它为我们提供了一种非常好的方式来表达我们的应用程序。我们只是准确地声明我们想要的东西,React/virtual-dom 会找出如何让你的场景看起来像这样。我们不必手动操作 DOM 或对之前的 DOM 状态感到困惑。我们也不必重新渲染整个场景,这可能比修补它的效率低得多。

什么是这样的例子unnecessary re-renders
2021-03-19 13:16:16
当您说“虽然虚拟 DOM 差异/补丁算法可能不是最佳解决方案”时,您是否想到了理论上更优化的解决方案?
2021-04-03 13:16:16
2021-04-06 13:16:16
这似乎并没有完全回答这个问题。React 要求您使用 setState 来表示状态已更改。如果你能做到,this.state.cats = 99你仍然需要脏检查来检查模型更改,就像 Angular 脏检查 $scope 树一样。这不是两种技术速度的比较,它只是声明 React 不进行脏检查,因为它有一个 Backbone 样式设置器。
2021-04-09 13:16:16
React 是否会对组件 props 进行脏检查?我问是因为没有 setProps() 函数。
2021-04-10 13:16:16

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

  • 批量 DOM 读/写操作。
  • 仅子树的有效更新。

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

  1. 模型脏检查:React 组件在setState调用时明确设置为脏,因此这里不需要比较(数据)。对于脏检查,(模型的)比较总是在每个摘要循环中发生。

  2. DOM 更新:DOM 操作非常昂贵,因为修改 DOM 也会应用和计算 CSS 样式、布局。从不必要的 DOM 修改中节省的时间可能比差异化虚拟 DOM 所花费的时间更长。

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

可悲的是,许多聪明的开发人员发明了“山”的技巧来处理“缓慢”的 DOM 等等,而不是将我们的共同注意力集中在修复浏览器本身并一劳永逸地摆脱 DOM 缓慢的问题上。这就像利用全人类的资源来研究治疗癌症和改善患者生活的方法,而不仅仅是治愈癌症本身。嘲笑。
2021-03-19 13:16:16
我相信只需要比较与更改的组件对应的虚拟 DOM 的部分,而脏检查会在每个摘要循环中发生,对于每个作用域上的每个值,即使没有任何更改。如果大量数据发生变化,那么 Virtual DOM 的效率会降低,但对于小数据变化则不然。
2021-03-21 13:16:16
说到 Angular,因为观察者也可以在消化时改变状态,$scope.$digest每个消化周期都会执行多次,所以它是多次完整数据比较与单次部分虚拟 DOM 树比较。
2021-03-22 13:16:16
@vsync DOM 需要在屏幕上显示内容。虚拟 DOM 没有。即使有一些理想的 DOM,创建虚拟 DOM 也会更快。
2021-04-09 13:16:16
实际上我也读过一些文章,所以我现在(至少在一般情况下)它是如何工作的,我只是想弄清楚为什么它比模型的脏检查更有效。并且 1) 是的,它不比较模型,但确实比较了更大的虚拟 dom 2) 模型的脏检查使我们能够仅更新需要的内容(就像 Angular 所做的那样)
2021-04-13 13:16:16

我真的很喜欢 Virtual DOM(尤其是服务器端渲染)的潜在力量,但我想知道所有的优点和缺点。

-- 操作

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

React.js 的虚拟 DOM

在此处输入图片说明

优点

  • 快速高效的“差异化”算法
  • 多个前端(JSX、超标)
  • 轻到足以在移动设备上运行
  • 大量的牵引力和思想共享
  • 可以在没有 React 的情况下使用(即作为一个独立的引擎)

缺点

  • DOM 的完整内存副本(更高的内存使用)
  • 静态和动态元素之间没有区别

Ember.js 的微光

在此处输入图片说明

优点

  • 快速高效的差分算法
  • 静态元素和动态元素的区别
  • 100% 兼容 Ember 的 API(无需对现有代码进行重大更新即可获得好处)
  • DOM 的轻量级内存表示

缺点

  • 仅用于 Ember
  • 只有一个前端可用

增量 DOM

在此处输入图片说明

优点

  • 减少内存使用
  • 简单的API
  • 轻松与许多前端和框架集成(从一开始就作为模板引擎后端)

缺点

  • 不如其他库快(这是有争议的,请参阅下面的基准)
  • 减少思想共享和社区使用
ReactJS 的 DOM 操作的表示对我来说似乎没什么。ReactJS 的虚拟 DOM 是完全改变的,而不是实际的 DOM - 对吗?我正在查看引用的文章引用的原始文章,这是我所看到的 - teropa.info/images/onchange_vdom_change.svgteropa.info/blog/2015/03/02/...
2021-04-12 13:16:16

这是 React 团队成员 Sebastian Markbåge 的评论,它阐明了一些观点:

React 对输出进行差异处理(这是一种已知的可序列化格式,DOM 属性)。这意味着源数据可以是任何格式。它可以是不可变的数据结构和闭包内的状态。

Angular 模型不保留引用透明度,因此本质上是可变的。您改变现有模型以跟踪更改。如果您的数据源每次都是不可变数据或新数据结构(例如 JSON 响应)怎么办?

脏检查和 Object.observe 不适用于闭包范围状态。

这两件事显然非常限制功能模式。

此外,当您的模型复杂性增加时,进行脏跟踪的成本会越来越高。然而,如果你只在可视化树上做 diff,比如 React,那么它不会增长太多,因为你能够在任何给定点在屏幕上显示的数据量受到 UI 的限制。上面皮特的链接涵盖了更多的性能优势。

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

实际上关于最后一段:它应该是错误的:模型比虚拟 dom 大,因为对于每个模型值,(在大多数情况下)至少有一个虚拟 dom 元素(通常不止一个)。为什么我想要没有显示的模型?
2021-03-22 13:16:16
分页缓存集合。
2021-03-24 13:16:16

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:
  1. 浏览器需要解析 HTML
  2. 它删除了 elementId 的子元素
  3. 用新值更新 DOM 值
  4. 为父子重新计算css
  5. 更新布局,即每个元素在屏幕上的精确坐标
  6. 遍历渲染树并将其绘制在浏览器显示上

重新计算 CSS 和更改的布局使用复杂的算法,它们会影响性能。

以及更新 DOM 属性,即。值。它遵循一个算法。

现在,假设你直接更新 10 次 DOM,那么以上所有步骤都会一一运行,更新 DOM 算法需要时间来更新 DOM 值。

这就是 Real DOM 比 Virtual DOM 慢的原因。

是的,在这两种情况下,我们都在更新 dom,但在虚拟 dom 的情况下,它只更新特定的键(由不同的算法唯一定义)字段或元素标签。而更新 dom 会更新或完全刷新整个 dom。
2021-03-17 13:16:16
我从hackernoon.com/virtual-dom-in-reactjs-43a3fdb1d130看到了这篇文章如果您不是作者,也许最好指出出处。
2021-03-25 13:16:16
关于示例,如果您直接或通过虚拟 dom 修改 dom,那么最终对于这两种情况,您都在更改 dom。
2021-03-28 13:16:16
“这就是真实 DOM 比虚拟 DOM 慢的原因。” 不,先生,你只是错了。
2021-04-06 13:16:16