咱们老是或多或少的据说过直接操做DOM是低效和缓慢的。然而,咱们几乎没有可用的数据来支持这个观点。关于React虚拟DOM的使人愉悦的地方在于web开发过程当中,它采用了更加高效的方式来更新view层。javascript
咱们把使用React的其余好处姑且放到一边,例如单项绑定和组件化。本节我讲详细的讨论一下虚拟DOM,随后公正的抉择为何使用React而不是其余UI库(或者任何UI库都不使用)。java
在反应式的系统中两个最重要的idea应该是事件驱动和对数据变化的响应。react
DOM用户接口组件有内部状态,当不管什么时候有状况发生变化的时候,更新浏览器并非像简单的从新生成DOM那么简单。举个例子,若是Gmail曾经这么作的话,由于浏览器窗口为了显示新的信息,须要不断的刷新整个页面,若是你正在写邮件的话,全部的都会被清除,你必定会常常恼怒不已。程序员
DOM的这种状态方式决定了为何咱们须要一个用户界面库,由于这些库提供了一些解决方案,例如键/值 观察(在Ember库中使用了此方法),或者脏值检测(Angular使用了此方法)。UI库能够观察数据模型的改变,而后在改变发生的时候只改变对应的部分DOM,或者观察DOM改变,而后更新数据模型。web
这种观察和更新的模式叫作双向绑定,这种方式经常让与用户界面的工做更加复杂和让人困惑。算法
React的虚拟DOM与其余库的不一样之处在于从程序员的角度看,这种模式更加的简单。你只须要写纯javascript,而后更新React组件,React将为你更新DOM。数据绑定并无和应用程序搅和在一块儿。浏览器
React使用单向数据绑定使得事情变得更加简单,每一次在ReactUI的input域中输入内容,React并不直接改变状态。相反,React更新数据模型,随后引发UI更新,你输入的文字将在域中出现。babel
关于虚拟DOM的不少演讲和文章都指出,尽管如今jiavascript的引擎已经很快了,可是读取和写入浏览器的DOM仍是很慢,app
这不是特别的准确。DOM是很快的。增长和去除DOM节点就是设置一些javascript对象的属性,这才是简单的操做,这并非须要作不少的工做。dom
真正慢的地方自在于,每次DOM改变的时候,都须要在浏览器中进行渲染。每一次DOM改变的时候,浏览器都须要从新计算CSS,进行布局处理,而后从新渲染页面。这都须要时间。
浏览器的开发者持续不断的工做来缩短渲染页面的时间。最关键的须要完成的事情是最小化DOM改变,而后批处理DOM变化,在必要的时候才从新渲染页面。(目前原生浏览器仍是没法作到)
这种批处理DOM改变的策略,把咱们提高到了一个更加抽象的层次,这也是React虚拟DOM背后的idea。
与真实DOM类似,虚拟DOM也是节点树,以对象的形式列出内容,属性。React的render方法从React组建中建立节点树,由于动做改变等引发数据模型变化的时候,React更新节点树。
每次React app内部的数据改变,用户界面的虚拟DOM都会构建。
这里就是最有趣的地方,在React中更新浏览器DOM须要三步: 1. 每次数据模型变化的时候,虚拟DOM节点树都会从新构建。 2. React依赖某个算法(称之为diff算法)来与上一个虚拟DOM节点数进行比较,只有在不一样的状况下才从新进行计算。 3.全部的变化要通过批处理,完成以后,真实DOM才进行更新。
有人认为只要有一点改变就从新构造整个虚拟DOM节点树有点浪费,可是他没有说起一个事实,React在内存中存储有两个虚拟DOM树。
可是,真实状况是渲染虚拟DOM老是比直接渲染浏览器DOM快。这种论断与你使用的浏览器也没多大的关系。
我不会作一些基准测试,由于已经有不少开发者建立了不少测试来搞清楚React虚拟DOM方法是否比原生的DOM渲染更加快速。可是频繁的结论显示彷佛不是这样,可是由于不少测试都是不实际的,因此这些测试结果也可有可无。
简单来讲,虚拟DOM就是把全部浏览器为了最小化DOM操做,这些对于开发者来讲透明的操做进行了抽象。这层额外的抽象的缺点就是增长了CPU的开销。
这里有一个"hello,world"的例子,使用了原生的DOM操做:
随后咱们在React中作相同的事情。在这里请注意咱们须要包含React,React DOM 和babel,其中babel负责把在render方法中的类XML的代码进行转换成原生的javascript。
结果显示,本地方法更加的快速。这并非开玩笑,让咱们看一下证据。
这里是加载和渲染真实DOM的性能分析图。(来源于Chrome)
这里是在一样的浏览器中加载和展现React的"hello,world"应用时间线。
请注意本质上来讲,事情是相同的。React比直接操做DOM慢,并且慢了不少。那么,与jQuery比又如何呢?
从分析图中,咱们能够看到,jQuery进行展现最简单的hello,world的应用比原生的纯javascript满了50毫秒,可是jQuery版本和原声版本都是React的3倍。
因此,很清晰,若是要说哪个更快,原生的javascript和jQuery无疑略胜一筹。
可是,使用库老是要比不使用库慢一些,这显然是再正常不过了,在内存里进行构建DOM,而后再进行真实的DOM操做更慢,也是很符合逻辑的状况。
废话说多了,如今让咱们准确思考一下,怎么使得虚拟DOM加载更快。
个人"hello world"项目对于React来讲是不公平的,缘由在于他们仅仅处理的是初次渲染页面的性能比较。React设计的目的是用来更新网页。
由于虚拟DOM的存在,每一次数据模型的改变都会触发虚拟用户接口的刷新。这与其余库进行直接的DOM更新是不同的。虚拟DOM实际上使用了更少的内训,由于它不须要在内存中设置观察者。
然而,每一次动做发生的时候,在内存中比较虚拟DOM也是低效的。这须要大量的CPU运算。
由于这个愿意,React开发者在决定须要渲染什么的时候并非彻底被动的。若是你知道特定的动做不会影响特定的组件,你能够告诉React不要去分析组件差异,这无疑能够大大节省资源,加快应用程序的性能。示范操做中的React程序是能够进行性能提高的。
真实状况是,没办法准确的知道虚拟DOM是否比直接进行DOM操做更快。由于这依赖于不少变量,尤为是和你怎么优化程序密切相关。
这并非革命性或者使人惊讶的事情,每一个人使用的工具都是挺好的。React和虚拟DOM给予咱们的,是用一种简单的方式进行UI渲染,它提供给咱们一种更加简便的方式来更新浏览器。这种简化能够大大释放咱们的脑力负担,使得优化用户界面更加的容易。这才是React真正好处所在的地方,若是处理获得,使用React,兼具性能和生产力,何乐而不为呢?
原文地址:www.accelebrate.com/blog/the-re…
做者: Chris Minnick
说明:原文有一处举了一个100000个墨西哥玉米卷的例子,只是想说明不用每一次拿一个玉米卷,而是等待想拿的玉米卷肯定以后而后在进行运输到本身国家进行消费。本质上仍是映射React的工做方式,原文闲的稍加啰嗦,有删节。
总结: 本文核心有两点:1.稍微介绍一下React的虚拟DOM和原生DOM的区别和联系。2.文末点出,虚拟DOM若是处理获得,是能够处理好性能问题的,可是React的真正好处在于,它的模块化思想,释放了生产力。
颠覆:文中有几个观点须要从新审视,咱们也常常据说直接操做DOM是低效的,可是这种低效在什么地方,彷佛也没有国内的开发者进行准确的数据论证比较,做者给出了它的解释,直接操做DOM并不低效,低效的地方在于渲染页面的过程繁杂浪费时间,相比于React批处理以后只渲染一遍无疑是高效了不少。