为什么React的Virtual DOM概念被认为比脏模型检查更具性能?

时间:2014-01-14 08:57:16

标签: javascript dom reactjs virtual-dom

我在React看到了一个http://www.youtube.com/watch?v=x7cQ3mrcKaY开发者讲话,而发言人提到模型的脏检查可能很慢。但是,由于虚拟DOM在大多数情况下应该比模型更大,所以虚拟DOM之间的差异实际上是不是很差,因为虚拟DOM会更大吗?

我非常喜欢Virtual DOM的潜在力量(特别是服务器端渲染),但我想知道所有的优点和缺点。

6 个答案:

答案 0 :(得分:469)

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

  1. 我什么时候重新渲染?答案:当我发现数据很脏时。
  2. 如何有效地重新渲染?答案:使用虚拟DOM生成真正的DOM补丁
  3. 在React中,每个组件都有一个状态。这种状态就像你可能在淘汰赛或其他MVVM风格的库中找到的一个可观察的状态。从本质上讲,React知道何时重新渲染场景,因为它能够观察到这些数据何时发生变化。脏检查比可观察的慢,因为您必须定期轮询数据并以递归方式检查数据结构中的所有值。相比之下,在状态上设置一个值会向一个监听器发出一个状态已经发生变化的信号,因此React可以简单地监听状态上的变化事件并排队重新渲染。

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

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

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

答案 1 :(得分:128)

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

  • 批量DOM读/写操作。
  • 仅对子树进行高效更新。

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

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

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

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

答案 2 :(得分:72)

  

我非常喜欢Virtual DOM的潜在力量(特别是   服务器端渲染)但我想知道所有的利弊。

     

- OP

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

  

React.js'虚拟DOM

     

enter image description here

     

赞成

     
      
  • 快速高效"差异化"算法
  •   
  • 多个前端(JSX,hyperscript)
  •   
  • 轻量级足以在移动设备上运行
  •   
  • 很多牵引力和思想分享
  •   
  • 可以在没有React的情况下使用(即作为独立引擎)
  •   
     

CONS

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

Ember.js'微光

     

enter image description here

     

赞成

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

CONS

     
      
  • 只能在Ember中使用
  •   
  • 只有一个前端可用
  •   
           

增量DOM

     

enter image description here

     

赞成

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

CONS

     
      
  • 没有其他图书馆快(这是有争议的,请参阅下面的基准)
  •   
  • 减少思想共享和社区使用
  •   

答案 3 :(得分:36)

以下是React团队成员SebastianMarkbåge发表的评论,该评论揭示了一些亮点:

  

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

     

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

     

脏检查和Object.observe对闭包范围状态不起作用。

     

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

     

此外,当您的模型复杂性增加时,进行脏跟踪变得越来越昂贵。但是,如果你只在视觉树上进行差异化,比如React,那么它就不会增长太多,因为你能够在任何给定点在屏幕上显示的数据量受到UI的限制。 Pete上面的链接涵盖了更多的性能优势。

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

答案 4 :(得分:0)

您可以阅读这篇{https://reactkungfu.com/2015/10/the-difference-between-virtual-dom-and-dom/}文章,以了解Real DOM和Virtual DOM。希望对您有帮助!

答案 5 :(得分:-2)

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

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

以下是使用Virtual Dom的原因(来源https://hackernoon.com/virtual-dom-in-reactjs-43a3fdb1d130):

  

当你这样做时:

document.getElementById('elementId').innerHTML = "New Value" Following thing happens:
     
      
  1. 浏览器需要解析HTML
  2.   
  3. 删除elementId
  4. 的子元素   
  5. 使用新值更新DOM值
  6.   
  7. 重新计算父母和子女的css
  8.   
  9. 更新布局,即每个元素在屏幕上精确坐标
  10.   
  11. 遍历渲染树并将其绘制在浏览器显示屏上
  12.         

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

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

现在,假设您直接更新DOM 10次,那么上述所有步骤将逐个运行,更新DOM算法需要时间来更新DOM值。

这就是Real DOM比虚拟DOM慢的原因。