ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

我认为您也可以提及这次谈话youtube.com/watch?v=-DX3vJiqxm4,他在其中专门谈到了基准。

M
Matt Esch

我是 virtual-dom 模块的主要作者,所以我或许能够回答您的问题。实际上这里有2个问题需要解决

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

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

虚拟 DOM 用于有效地重新渲染 DOM。这实际上与脏检查您的数据无关。您可以使用带或不带脏检查的虚拟 DOM 重新渲染。你是对的,计算两个虚拟树之间的差异有一些开销,但虚拟 DOM 差异是关于了解 DOM 中需要更新的内容,而不是你的数据是否发生了变化。实际上,diff 算法本身就是一个脏检查器,但它用于查看 DOM 是否脏。

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

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


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

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

批处理 DOM 读/写操作。

仅有效更新子树。

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

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

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


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

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

React 不是唯一的 DOM 操作库。我鼓励您通过阅读包含详细说明和基准的article from Auth0来了解替代方案。正如你所问的,我将在这里强调它们的优缺点:

React.js 的虚拟 DOM 优点 快速高效的“差异化”算法 多个前端(JSX、超脚本) 轻量级,可以在移动设备上运行 大量的牵引力和思想共享 可以在没有 React 的情况下使用(即作为独立引擎) 缺点 完全在内存中DOM 的副本(更高的内存使用) 静态元素和动态元素之间没有区别 Ember.js 的 Glimmer PROS 快速高效的差异算法 静态和动态元素之间的区别 100% 与 Ember 的 API 兼容(无需对现有元素进行重大更新即可获得好处代码)DOM 的轻量级内存表示 缺点 仅在 Ember 中使用 只有一个前端可用 增量 DOM 优点 减少内存使用 简单的 API 轻松与许多前端和框架集成(从一开始就作为模板引擎后端) 缺点 不是与其他库一样快(这是有争议的,请参阅下面的基准)更少的思想分享和社区使用


ReactJS 的 DOM 操作的表示对我来说似乎没什么。 ReactJS 的虚拟 DOM 是完全改变的,而不是实际的 DOM——对吗?我正在查看引用文章引用的原始文章,这就是我所看到的 - teropa.info/images/onchange_vdom_change.svgteropa.info/blog/2015/03/02/…
C
Community

以下是 React 团队成员 Sebastian Markbåge 的评论,它提供了一些启示:

React 对输出进行区分(这是一种已知的可序列化格式,DOM 属性)。这意味着源数据可以是任何格式。它可以是不可变的数据结构和闭包内部的状态。 Angular 模型不保留引用透明度,因此本质上是可变的。您改变现有模型以跟踪更改。如果您的数据源每次都是不可变数据或新数据结构(例如 JSON 响应)怎么办?脏检查和 Object.observe 不适用于闭包范围状态。这两件事显然非常限制功能模式。此外,当您的模型复杂性增加时,进行脏跟踪变得越来越昂贵。然而,如果你只在可视化树上进行差异化,比如 React,那么它就不会增长太多,因为你能够在任何给定点在屏幕上显示的数据量都受到 UI 的限制。皮特上面的链接涵盖了更多的性能优势。

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


实际上关于最后一段:它应该是错误的:模型大于虚拟 dom,因为对于每个模型值(在大多数情况下)至少有一个虚拟 dom 元素(通常远不止一个)。为什么我想要未显示的模型?
对缓存的集合进行分页。
M
Mridul Das

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

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


S
Silicum Silium

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

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

以下是使用 Virtual Dom 的要点(来源 Virtual DOM in ReactJS):

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

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

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

这就是为什么 Real DOM 比 virtual DOM 慢的原因。


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

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅