在頁面中如何大面積操做DOM的話,性能確定是一個很大的問題,然而聰明的ReactJS實現了Virtual DOM技術,這是他的亮點之一。將組件的DOM結構映射到這個Virtual DOM對象上,而且ReactJS還實現了一套Diff算法,這也是他亮點之一。當須要更新組件的時候,會經過Diff算法找到要變動的內容,最後,在把這個修改更新到實際的DOM節點上,因此,組件更新實際上不是真的渲染整個DOM樹,而是指更新須要修改的DOM節點,這樣在性能上會比原生DOM快不少。javascript
那麼這個Virtual DOM究竟是什麼?假設咱們要建立一個組件,其結構以下:java
1 <ul> 2 <li> 3 A 4 </li> 5 <li> 6 <ul> 7 <li> 8 B 9 </li> 10 </ul> 11 </li> 12 </ul>
而後咱們開始建立原生組件:算法
1 //用JSX實現的 2 var root = <ul> 3 <li>A</li> 4 <li> 5 <ul> 6 <li> 7 B 8 </li> 9 </ul> 10 </li> 11 </ul>; 12 //用javascript實現的 13 var A = React.createElement('li',null,'A'); 14 var B = React.createElement('ul',null,React.createElement('li',null,'B')); 15 var root = React.createElement('ul',null,A,B); 16 //輸出虛擬的DOM結構 17 console.log(root);
打開控制檯咱們就能看到輸出的一個javascript的對象,沒錯這就是咱們所說的Virtual DOM對象;瀏覽器
接下來咱們看看Diff算法在ReactJS中的體現,首先咱們藉助瀏覽器中的MutationObderver功能,對頁面元素進行監聽ide
1 'use strict'; 2 const mutation = window.MutationObserver 3 ||window.WebKitMutationObserver 4 ||window.MozMutationObserver; 5 if(!!mutation){ 6 const mutationObserver = new mutation((item) => { 7 item.forEach((item) => { 8 console.log(item); 9 }); 10 }); 11 const options = { 12 "childList" : true, 13 "attributes" : true, 14 "characterData" : true, 15 "subtree" : true, 16 "attributeOldValue" : true, 17 "characterDataOldValue" : true 18 }; 19 mutationObserver.observe(document.body,options); 20 }
而後再把ReactJS組件的生命週期進行封裝,便於組件來調用性能
1 'use strict'; 2 const LifeCycle = name => { 3 let obj = { 4 name : name 5 }; 6 return Object.assign(obj,Cycle); 7 }; 8 const Cycle = { 9 getDefaultProps:function(){ 10 console.log(this.name,'getDefaultProps'); 11 return {}; 12 }, 13 getInitialState:function(){ 14 console.log(this.name,'getInitailState'); 15 return {}; 16 }, 17 componentWillMount:function(){ 18 console.log(this.name,'componentWillMount'); 19 }, 20 componentDidMount:function(){ 21 console.log(this.name,'componentDidMount'); 22 }, 23 componentWillRecieveProps:function(){ 24 console.log(this.name,'componentWillRecieveProps'); 25 }, 26 shouldComponentUpdate:function(){ 27 console.log(this.name,'shouldComponentUpdate'); 28 return true; 29 }, 30 componentWillUpdate:function(){ 31 console.log(this.name,'componentWillUpdate'); 32 }, 33 componentDidUpdate:function(){ 34 console.log(this.name,'componentDidUpdate'); 35 }, 36 componentWillUnmount:function(){ 37 console.log(this.name,'componentWillUnmount'); 38 } 39 };
接着定義須要用到的組件學習
1 'use strict'; 2 //A組件 3 let A = React.createClass({ 4 mixins:[LifeCycle('A')], 5 render:function(){ 6 console.log('A','render'); 7 return ( 8 <ul> 9 <li>A</li> 10 <li> 11 <ul> 12 {this.props.children} 13 </ul> 14 </li> 15 </ul> 16 ); 17 } 18 }); 19 //B組件 20 let B = React.createClass({ 21 mixins:[LifeCycle('B')], 22 render:function(){ 23 console.log('B','render'); 24 return ( 25 <li>B</li> 26 ); 27 } 28 }); 29 //C組件 30 let C = React.createClass({ 31 mixins:[LifeCycle('C')], 32 render:function(){ 33 console.log('C','render'); 34 return ( 35 <li>C</li> 36 ); 37 } 38 }); 39 //D組件 40 let D = React.createClass({ 41 mixins:[LifeCycle('D')], 42 render:function(){ 43 console.log('D','render'); 44 return ( 45 <li>D</li> 46 ); 47 } 48 });
最後,定義咱們的主邏輯this
1 console.log('----------------first-----------------'); 2 React.render( 3 <A><B></B><C></C></A>, 4 document.body 5 ); 6 7 setTimeout(() => { 8 console.log('-----------------second--------------'); 9 React.render( 10 <A><B></B><D></D><C></C></A>, 11 document.body 12 ); 13 },1000);
常規的作法就是將B和C組件先刪除,而後依次建立和插入A,B,C組件。接下來咱們打開瀏覽器的控制檯看下ReactJS是怎麼作的 spa
從日誌中能夠看出,React的Diff算法的結果是,A組件不變,先將C組件進行刪除,而後在建立D組件並插入D組件,最後建立並插入C組件,這比咱們常規的作法省去了對B組件的刪除操做。這樣其實並無將Diff算法的做用發揮到極限。下面咱們調整下邏輯代碼:3d
1 console.log('----------------first-----------------'); 2 React.render( 3 <A key="A"><B key="B"></B><C key="C"></C></A>, 4 document.body 5 ); 6 7 setTimeout(() => { 8 console.log('-----------------second--------------'); 9 React.render( 10 <A key="A"><B key="B"></B><D key="D"></D><C key="C"></C></A>, 11 document.body 12 ); 13 },1000);
主要的修改就是給每一個組件加了一個key屬性,此時再來運行下代碼看下控制檯的日誌:
能夠看出,此次Diff算法與以前的有很大的不一樣。B組件不變,C組件不變,只是在C組件以前建立並插入了D組件。
以上即是Virtual DOM和Diff算法的一些簡單的使用和分析,學習來源:
http://calendar.perfplanet.com/2013/diff/ 《React Native入門與實踐》