繁体   English   中英

为什么说 React 的 Virtual DOM 概念比 dirty model 检查性能更高?

[英]Why is React's concept of Virtual DOM said to be more performant than dirty model checking?

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

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

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

  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 状态感到困惑。 我们也不必重新渲染整个场景,这可能比修补它的效率低得多。

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

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

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

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

  2. 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 不适用于闭包范围状态。

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

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

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

您可以阅读本文( Virtual DOM和DOM之间的区别 ),了解Real DOM和Virtual DOM。 希望它能帮到你!

在 React 中,您的每个组件都有一个 state。这个 state 就像您可能在 knockout 或其他 MVVM 样式库中找到的可观察对象。 本质上,React 知道何时重新渲染场景,因为它能够观察到此数据何时发生变化。 脏检查比可观察对象慢,因为您必须定期轮询数据并递归检查数据结构中的所有值。 相比之下,在 state 上设置一个值将向侦听器发出信号,表明某些 state 已经更改,因此 React 可以简单地侦听 state 上的更改事件并排队重新渲染。虚拟 DOM 用于高效地重新渲染DOM。 这与脏检查您的数据并没有真正的关系。 您可以使用带或不带脏检查的虚拟 DOM 重新渲染。 你是对的,计算两个虚拟树之间的差异有一些开销,但虚拟 DOM 差异是关于了解 DOM 中需要更新的内容,而不是你的数据是否已更改。 事实上,diff 算法本身就是一个脏检查器,但它是用来查看 DOM 是否脏的。

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

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 属性,即。 值。 它遵循一个算法。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM