繁体   English   中英

React 的 Virtual DOM 到底有多快?

[英]How exactly is React's Virtual DOM faster?

我知道 React 的虚拟 DOM 有两个 arguments 更快 -

  1. 它只更新那些实际需要更新的元素(使用差异)。

  2. 它批量更新,因此我们只更新一次真实的 DOM。 因此,重绘也只进行一次,否则将进行多次。

我对这两点都有疑问-

  1. 据我所知,所有现代浏览器都足够高效,只更新 DOM 中所需的元素。 例如,如果我有两个“p”标签,并且我通过单击按钮更改了其中一个 p 标签中的文本,那么 safari 只会更新该 p 标签(我已经使用油漆闪烁验证了这一点)。 那么如果第 1 点已经被浏览器实现了,那么它有什么优势呢?

  2. React 究竟是如何批处理更新的? 最终 React 还必须使用 DOM api 来更新真实的 DOM。 那么为什么如果我们直接使用 DOM api 那么更改不会被批处理,而当 React 使用它时它们会被批处理?

我找到了我的问题的答案。

关键是要了解 Virtual DOM 的用途。

首先我们必须看看 React 采用什么方法来渲染组件。

不同的 javascript 框架采用不同的方法来检测数据 model 的变化并将它们呈现在视图上。

考虑 AngularJS。 当我们在 Angular 模板中引用我们的数据时,例如在像 {{foo.x}} 这样的表达式中,Angular 不仅会呈现该数据,还会为该特定值创建一个观察者。 每当我们的应用程序发生任何事情(点击事件、HTTP 响应、超时)时,所有的观察者都会运行。 如果观察者中的值已更改,则该值将在 UI 中重新呈现。 通过运行所有观察者 AngularJS 本质上是找出它需要在哪里进行更改。 运行这些观察者的过程称为脏检查。

React 采用了不同的方法。 每当 React 组件中发生 state 更改时,React 不会找出在哪里进行更改(如 AngularJS),而是从头开始重新渲染整个 UI(具有更新的状态)。

但是 React 的这种方法有一个问题。 重新渲染整个 UI 意味着重新渲染整个 DOM 树。 这是一个问题,因为 DOM 更新是一个缓慢的过程(由于回流和重绘)。

这就是 React 的虚拟 DOM 的用武之地。虚拟 DOM 只是 javascript 对象形式的真实 DOM 的表示。 它只是存在于 memory 中的普通 javascript 对象的树数据结构。 与 Real DOM 相比,Virtual DOM 的渲染要快得多,因为它永远不会在屏幕上渲染(不需要进行回流或重新绘制)。

那么 Virtual DOM 是如何解决这个问题的呢? 当我们加载我们的应用程序时,React 会创建一个虚拟 DOM,它是真实 DOM 的精确虚拟副本。 每当组件中发生 state 更改时,React 不会重新渲染整个 Real DOM,而是渲染一个全新的 Virtual DOM(具有更新的状态)。 然后它在旧的虚拟 DOM(真实 DOM 的初始副本)和这个新的虚拟 DOM(在 state 更改后呈现)之间进行比较,以找出它们之间的变化,它只做真实 DOM 中的那些变化。 通过这种方式,整个 UI 被重新渲染(通过渲染一个全新的 Virtual DOM),但只在 Real DOM 中完成了所需的最少更改。

因此,当说“使用 Virtual DOM React 只更新那些需要更新的元素”(我的问题中的第 1 点)时,这意味着在 Virtual DOM React 的帮助下,它正在克服其自身方法的局限性(方法从头开始渲染整个 UI)。

这个答案也解释了同样的概念。

I have seen some answers that state that DOM manipulation using React is faster than using the DOM api because the DOM api re-renders the entire DOM tree whereas React re-renders only those parts of the DOM tree that need to be changed. 这不是真的。 所有现代浏览器都足够高效,只更新 DOM 树中需要更改的部分。 这可以使用浏览器的开发人员工具中的绘画闪烁来验证(另请参阅此答案和此答案)。 即使我们假设 DOM api 确实重新渲染了整个 DOM 树,但这个推理仍然是错误的,因为 React 本身的内部代码必须使用 DOM api 来更新 DOM。 如果 DOM api 确实重新渲染了整个 DOM 树,那么 React 也会重新渲染整个 DOM 树,因为最终它也使用 DOM api 来更新 DOM。


至于第二点,React 实际上让我们更容易进行批处理。

在 React 中,虽然读取是在 Real DOM 上完成的,但写入(状态更改)不是在 Real DOM 上完成的。 相反,写入是排队的。 然后当我们所有的读写都处理完后,一个新的 Virtual DOM 就会基于这些写来构建。 然后在新旧 Virtual DOM 之间进行差异化,然后 React 将所需的更改写入 Real DOM 以更新它。 因此,最终在 Real DOM 上的所有写入都在一次回流中一起完成。

但是我们也可以在没有 React 的情况下手动编写代码,首先完成所有读取,然后完成所有写入。 React 使批处理更容易,因为使用 React 我们不必关心一起进行读取和写入,React 会自动为我们批处理写入。 所以 React 不会让事情变得很快。 它使事情变得更容易。


总之,我们可以说 React 实际上并不快。 这更容易。 As Pete Hunt says in this video , "React is not magic. Just like you can drop into assembler with C and beat the C compiler, you can drop into raw DOM operations and DOM API calls and beat React if you wanted to. However, using C or Java or JavaScript is an order of magnitude performance improvement because you don't have to worry...about the specifics of the platform. With React you can build applications without even thinking about performance and the default state is fast." .

Rich Harris 的这篇文章还指出,“Virtual DOM 很快”是一个神话。

在此处输入图像描述

一旦 React 知道哪些虚拟 DOM 对象发生了变化,那么 React 只会更新真实 DOM 中的那些对象。 与直接操作真实 DOM 相比,这使得性能要好得多。 这使得 React 作为高性能 JavaScript 库脱颖而出。

关于批量更新:

React 遵循批量更新机制来更新真实的 DOM。 因此,导致性能提高。 这意味着对真实 DOM 的更新是分批发送的,而不是为 state 中的每个更改发送更新。

UI 的重绘是最昂贵的部分,React 有效地确保真正的 DOM 只接收批量更新来重绘 UI。

暂无
暂无

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

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