這篇文章只是我的理解,有什麼差別和謬誤還望你們指出:前端
不知道是從何時開始,寫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