w3ctech

React Virtual DOM、Ember Glimmer和Incremental DOM技术哪家强

原文链接 React Virtual DOM vs Incremental DOM vs Ember’s Glimmer: Fight

本文将探索3种构建动态DOM的技术,并通过一些基准测试对比3种技术的性能快慢,最后我会给出在项目中哪种技术更加适合以及为什么。 介绍 现在已经有许多DOM操作的框架和类库。在这些类库之中,专注于性能而被关注最多是React.js,Ember.js以及最新的Incremental DOM。React和Ember已经远不是简单的对DOM进行构建/更新,而Incremental DOM 专注在构建DOM树和动态更新。下面将对比测试这三个类库的快慢。

enter image description here

在深入细节之前,非web开发者可能会问什么是 DOM 操作,这里简单介绍一下。网页实际上是由不用元素构成的一个树形结构。元素按照HTML规范定义工作。通过组合这些元素,我们可以构建任意复杂的网站。而DOM树就是一个树形HTML元素的抽象表示,它由W3C规范定义并且被所有主流浏览器实现支持。

除了帮助将模型绑定到视图,这些类库能高效更新DOM,一般情形下的多次DOM操作会被自动合并成单次(或更少)的调用。比如某一次操作需要进行:

  1. 删除元素
  2. 添加元素
  3. 改变添加元素的属性

通过DOM接口进行如上操作会导致高开销的内容重新绘制和布局。通过虚拟模型就可以把上述分次操作合并成一次。

模板

用模板技术生成DOM很流行。开发中通过模板语法告诉编译器生成DOM树(或者HTML文档)。模板技术可以是HTML的扩展或者是全新设计语法。

本文介绍的三种技术并非都用了模板。比如React使用了JSX:一种Javascript的拓展语法,通过预编译的方式支持在Javascript里面插入类HTML的代码。然而Ember使用了一种叫Handlebars的模板语言。 Incremental DOM 并没有偏向特定的模板引擎,然而,Google赞助一个名叫Closure templates 的项目将被支持,Incremental DOM还可以和superviews.jsstarplate甚至JSX一起工作。

React.js 的虚拟DOM

React开发者对DOM操作引擎命名为虚拟DOM,她通过一系列的Javascript调用告诉类库生成一个内存的DOM树并且和数据的变动同步起来。虚拟DOM的核心是智能差量算法(smart deffing algorithm):当数据模型变动更新到内存DOM树上时,算法会生成同等效果,但最小需要更新DOM树的指令。所以在不同的状态下有两份内存DOM树。

enter image description here

声明:本文一些图出自:[excellent post explaining DOM manipulation libraries](http://teropa.info/blog/2015/03/02/change-and-its-detection-in-javascript-frameworks.html)

优点

  • 差量算法高效快速
  • 前端支持多种语法(JSX,hyperscript)
  • 对移动设备足够轻量
  • 发展迅速,关注度高
  • 可以脱离React使用(仅仅使用引擎)

缺点

  • 内存DOM导致高内存消耗
  • 没有区分静态和动态元素*

React最近在实现一个通过检测不变量来减少需要做差量化比较的元素。

Ember.js 的Glimmer

Glimmer是Ember.js最近的模板引擎,她借鉴引入了React的虚拟DOM技术同时保持了接口的一致性。需要指出的是开发者重写了整个引擎,并没有和虚拟DOM共享代码。 Glimmer区分了静态动态的组件,因此减少了需要检测的元素数量。这个区别得益于handlerbar引擎的高表述性。 Glimmer另外区分其他方案的关键实现是对于元素节点的存储和比较,是被存放在一个简单的流对象(就是一个简单的对象队列)而不是完整的类DOM节点。这样如果要计算下次需要更新的节点,只要比较节点的值是否改变,如果没有改变就不需要进行下一步操作。

enter image description here

优点

  • 高效快速的比较算法
  • 引擎区分静态和动态元素
  • 100%对Ember接口兼容(现有Ember用户不用改变代码)
  • 轻量化DOM的内存表达方案

缺点

  • 之能在Ember使用
  • 只有一种前端选择

Incremental DOM

相比而言,Incremental DOM尝试通过简单的方案:与其维护DOM树完整的、或者轻量话的内存拷贝,当数据改变的时候,Incremental DOM直接在真正的DOM元素上做比较。大家可能问为什么,如果就这么简单那为什么其它技术没有采用这种方案。简单的说:所有的方案都是在内存和速度上做一个权衡。而Incremental DOM,通过去除DOM树拷贝来减少内存的占用,实际上确实脏检查导致了性能下降。节省的内存对于手机或者其他内存宝贵的设备来说非常关键。大家可以关注我的另一篇博文:our article on Incremental DOM

enter image description here

优点

  • 减少内存占用
  • 接口简单明了
  • 容易集成到其它的前端框架(当然需要一开始就以它作为后端引擎)

缺点

  • 速度相对较慢(这个是有争议的,看下面的测试结果)
  • 关注度和社区使用较少
  • 性能测试

    我们选择这篇博文里dbmonster test app来做测试。Dbmonster是针对数据库集群行为的场景模拟出在table里面进行大量的行更新,一来是被开发出来测试Ember的性能的程序。我们使用了最新的React,Ember 1.x 和 2.x(都使用了Glimmer)和Incremental DOM。所有的测试都跑在Linux环境的Chromium 46(Core i5-5200U CPU)。每种测试跑5遍然后取平均值。

enter image description here

enter image description here

在有大块和小块垃圾收集的场景中。Incremental DOM表现出了预期的高效。React紧随第二但是在琐碎垃圾收集场景中大幅落后Incremental DOM。有意思的是Ember 1 到 2 的改进还是比较大的。

enter image description here

Ember在布局和绘画操作中所花时间这个场景中表现突出。Incremental DOM由于牺牲性能获取内存,不出意料的排在最后。React目前来看比较平衡。

enter image description here

这特图标显示出Chrome的丢帧数(不响应导致的停止绘画)。丢帧的结果是帧率低和画面停顿感。在这个场景中,Incremental DOM再次突起,更少用于处理GC的时间片段使得用户绘画的时间更多。React和Ember紧随其后。 一个没有反应在图标中的有趣的现象是,主观上会感觉Incremental DOM的响应更快。通过观察收集的数据,发现Incremental Dom相比对比技术的Javascript操作更少。当然,这和Incremental DOM是一个单纯的DOM操作类库,而React和Ember处理的东西更多:时间,数据传输等等。一个不用React的虚拟DOM的测试会很有意思。 我们看看最后完整总结的结果

这里有测试所用的代码。你需要安装ChromeDriver和所有Node.js的依赖(json2csv,brower-perf),然后运行命令 node run-benchmarks.js 。最后的测试结构卸载data.json(完整)和results.csv(总结)。

题外话:在Auth0使用React.js

在Autho,我们一直在评估最适合我们的技术。我们用React.js开发了 Passwordless Lock library。因为React没有对model技术的依赖使得它成为我们最好的选择,在其他方面,React在速度,内存占用,集成难度和文档、支持取得了一个很好的平衡。

注册使用我们的Passwordless Lock library或者看看代码。 结论 虚拟DOM,Glimmer和Incremental DOM都是动态操作DOM树的优秀方案。React.js的快速发展和轻量化是许多项目的不二选择。虽然高内存占用对于内存吃紧的移动设备上运行的大型网站会有问题,但是随着移动设备的硬件发展,这个问题正在逐步淡化。Incremental DOM花小钱办大事的效果让人眼前一亮,我们期望她能集成到Closure和其他库中。React和Ember在各自的实现方法中取得了很好的平衡。 当选择这几个技术的时候,最好关注技术的成熟度和是否容易集成。除非你对DOM的操作巨频繁(意思就是一般情况下,性能问题没那么突出),如果这样,请仔细的研究播客的结果并且针对你的场景生成测试数据。

w3ctech微信

扫码关注w3ctech微信公众号

共收到1条回复

  • Major GC Minor GC 丢帧数这些数据是怎么获取的?

    回复此楼