这篇文章只是我的理解,有什么差别和谬误还望你们指出:前端
不知道是从何时开始,写JavaScript的时候,脑壳里面就会一直回响着一句话,尽可能避免DOM操做,缘由是DOM操做比较消耗性能,特别是在复杂的DOM结构中进行DOM操做。而当咱们使用各类各样前端模板引擎的时候,更是没法避免不停地操做DOM。算法
React出于性能的考虑,为了不频繁操做DOM,采用了虚拟DOM结构(virtual DOM):性能优化
每当虚拟DOM树发生变化树发生变化时,React会将当前DOM树和以前的虚拟DOM树进行diff算法对比,获得虚拟DOM结构的区别,而后仅仅渲染差别部分。app
var MyComponent = React.createClass({ render: function() { if (this.props.first) { return <div className="first"><span>A Span</span></div>; } else { return <div className="second"><p>A Paragraph</p></div>; } } });
这里MyComponent执行render方法的结果并非一个真实的DOM节点,而是一个轻量级的JavaScript对象,即虚拟DOM。dom
若是咱们先插入组件:<MyComponent first={true} />;
React会建立真实DOM节点:<div className="first"><span>A Span</span></div>性能
将以前的组件替换为:<MyComponent first={false} />;
React会替换以前节点的属性:className="first"为className="second",同时替换子节点<span>A Span</span>为<p>A Paragraph</p>优化
最后移除组件;
React会移除节点<div className="second"><p>A Paragraph</p></div>this
若是将全部虚拟节点进行改变先后的diff算法比较,这一样是一件消耗性能的过程(两个树的比较复杂度为O(n^3)),React采用了如下优化方案,将性能优化到O(n)。spa
React将虚拟树进行分层比较,这是由于节点操做不多存在跨层级的(好比将子节点移动到父节点外,变成父节点的兄弟节点),大多操做可能是在兄弟节点之间的。以下图中,比较只会在相同颜色的兄弟节点之间进行,一旦节点被删除,则全部子节点都会被删除,不会进行比较。
假设有这样的状况,一个组件初始化时渲染了5个子节点,第二个时钟周期时向这5个子节点中间插入一个新的组件。这时,若是直接对比先后两个子节点树,新插入节点以后的全部子节点都会被从新渲染(C被替换为F,D被替换为C,E被替换为D),由于他们和以前的节点树不匹配。如同下图的状况:
React在组件插入的过程当中,只会将同级子节点按先后顺序排列起来,可是,若是给予每一个子节点一个惟一的key值,这样每一个子节点都能找到与之对应的节点进行比较。
节点diff算法只会在相同的组件类型上进行,意味着若是一个<Header>组件被替换成了<ExampleBlock>,这时先后节点树不会进行对比。React作出这样的取舍是由于耗费大量计算去匹配两个几乎不会类似的组件是一种浪费。而事实上,大多数用户会用大量的div去构建一个节点树,React在不会匹配不一样class的组件。
参考文章: http://www.infoq.com/cn/articles/react-dom-diff?from=timeline&isappinstalled=0