React: 一個用於構建用戶界面的JAVASCRIPT庫.html
React僅僅專一於UI層;它使用虛擬DOM技術,以保證它UI的高速渲染;它使用單向數據流,所以它數據綁定更加簡單;那麼它內部是如何保持簡單高效的UI渲染呢?react
React不直接操做DOM,它在內存中維護一個快速響應的DOM描述,render方法返回一個DOM的描述,React可以計算出兩個DOM描述的差別,而後更新瀏覽器中的DOM。git
就是說React在接收到props或者state更新時,React就會經過前面的方式更新UI。就算從新使用ReactDOM.render(<Component />, mountNode)
,它也只是看成props更新,而不是從新掛載整個組件。因此React整個UI渲染是比較快的。github
1. 若是更新的props和舊的同樣,這個時候很明顯UI不會變化,可是React仍是要進行虛擬DOM的diff,這個diff就是多餘的性能損耗,並且在DOM結構比較複雜的狀況,整個diff會花費較長的時間。算法
2. 既然React老是要進行虛擬DOM的diff,那麼它的diff規則是什麼?怎麼利用?瀏覽器
針對第一個問題React給咱們提供了 PureRenderMixin。
若是React組件是純函數的,就是給組件相同的props和state組件就會展示一樣的UI,可使用這個Minxin來優化React組件的性能。性能優化
var PureRenderMixin = require('react-addons-pure-render-mixin'); React.createClass({ mixins: [PureRenderMixin], render: function() { return <div className={this.props.className}>foo</div>; } });
ES6中的用法是數據結構
import PureRenderMixin from 'react-addons-pure-render-mixin'; class FooComponent extends React.Component { constructor(props) { super(props); this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this); } render() { return <div className={this.props.className}>foo</div>; } }
PureRenderMixin的原理就是它實現了shouldComponentUpdate,在shouldComponentUpdate內它比較當前的props、state和接下來的props、state,當二者相等的時候返回false,這樣組件就不會進行虛擬DOM的diff。框架
這裏須要注意:
PureRenderMixin內進行的僅僅是淺比較對象。若是對象包含了複雜的數據結構,深層次的差別可能會產生誤判。僅用於擁有簡單props和state的組件。dom
React雖然提供簡單的PureRenderMixin來提高性能,可是若是有更特殊的需求時怎麼辦?若是組件有複雜的props和state怎麼辦?這個時候就可以使用shouldComponentUpdate來進行更加定製化的性能優化。
boolean shouldComponentUpdate(object nextProps, object nextState) { return nexprops.id !== this.props.id; }
在React組件須要更新以前就會調用這個方法,若是這個方法返回false,則組件不更新;若是返回true,則組件更新。在這個方法內部能夠經過nextProps和當前props,nextState和當前state的對比決定組件要不要更新。
若是對比的數據結構比較複雜,層次較深,對比的過程也是會有較大性能消耗,又可能得不償失。
這個時候immutable.js就要登場了,也是fb出品,有人說這個框架的意義不亞於React,可是React光芒太強。它能解決複雜數據在deepClone和對比過程當中性能損耗。
注意:shouldComponentUpdate在初始化渲染的時候不會調用,可是在使用forceUpdate方法強制更新的時候也不會調用。
PureRenderMixin和shouldComponentUpdate的關注點是UI需不須要更新,而render則更多關注虛擬DOM的diff規則了,如何讓diff結果最小化、過程最簡化是render內優化的關注點。
React在進行虛擬DOM diff的時候假設:
一、擁有相同類的兩個組件將會生成類似的樹形結構,擁有不一樣類的兩個組件將會生成不一樣的樹形結構。
二、能夠爲元素提供一個惟一的標誌,該元素在不一樣的渲染過程當中保持不變。
DOM結構
renderA: <div /> renderB: <span /> => [removeNode <div />], [insertNode <span />
DOM屬性
renderA: <div id="before" /> renderB: <div id="after" /> => [replaceAttribute id "after"]
以前插入DOM
renderA: <div><span>first</span></div> renderB: <div><span>second</span><span>first</span></div> => [replaceAttribute textContent 'second'], [insertNode <span>first</span>]
以前插入DOM,有key的狀況
renderA: <div><span key="first">first</span></div> renderB: <div><span key="second">second</span><span key="first">first</span></div> => [insertNode <span>second</span>]
因爲依賴於兩個預判條件,若是這兩個條件都沒有知足,性能將會大打折扣。
一、diff算法將不會嘗試匹配不一樣組件類的子樹。若是發現正在使用的兩個組件類輸出的 DOM 結構很是類似,你能夠把這兩個組件類改爲一個組件類。
二、若是沒有提供穩定的key(例如經過 Math.random() 生成),全部子樹將會在每次數據更新中從新渲染。
使用PureRenderMixin、shouldComponentUpdate來避免沒必要要的虛擬DOM diff,在render內部優化虛擬DOM的diff速度,以及讓diff結果最小化。
使用immutable.js解決複雜數據diff、clone等問題。