天天看點

operamasks-ui和其它js架構性能對比

一、前言

       前段時間我們團隊推出了operamasks-ui ,得到了業界的一些關注,首先謝謝大家的關注,你們的關注就是我們團隊的動力。

       在推出一段時間之後也得到了一些回報,有元件需求的回報,有元件bug的回報,還有性能方面的一些回報,希望我們能給出一個性能對比報告,和各個其它js架構做一個橫向的對比,讓選擇的時候能心中有數。

      針對以上問題我們的測試人員和開發人員先選擇了omTree和其它架構對比,做了一系列的測試資料,這裡要聲明的是我們不是要證明我們的元件有多強,隻是想真實的對比一下,是好貨拿出來溜溜嘛,同時也發現自己的不足,繼續改進元件。

      測試的前提:元件功能一緻、資料和資料源一緻。

二、名詞解釋

Render Time :使用者在頁面上看到第一個内容的時間。當開始渲染時使用者是可以在浏覽器中看見内容的,而有内容的時候 document.body.offsetHeight 應該是大于 0 的,是以根據這一特點使用 timer 來檢查。(網上資料顯示 FireFox 可以通過在 window 上注冊“ MozAfterPaint ”事件來計算浏覽器開始渲染的時間,但是實際測試時發現 FireFox7.0 根本監控不到“ MozAfterPaint ”事件,是以也根據 document.body.offsetHeight 大于 0 進行測試)

Dom Ready :文檔解析完成的時間,目前對于文檔解析具體包括哪些操作沒有具體的答案,但文檔解析至少應該包括以下操作: HTML 文檔分析以及 DOM 樹的建立、外鍊腳本的加載、外鍊腳本的執行以及内聯腳本的執行,但不包括圖檔、 iframe 等其它資源的加載。

Page Load : window.onload 事件觸發的時間。與 DOM Ready 時間相比, Page Load 的時間往往要更靠後一些,因為 Page Load 不僅僅是 HTML 文檔解析完畢還包括了所有資源加載所需要的時間,例如圖檔資源的加載、 iframe 的加載等。

Show Time :元件内容展現時間,即 tree 完全展現的時間。

CPU 監控 :通過 ProcessExplorer 監控通路案例時浏覽器的 CUP 占用率。

三、概述

本次測試主要是對 operamask-ui 與 easyui 、 extjsui 、 ligerui 幾個産品進行前端性能對比測試,被測元件為 tree , tree 展示 10 個父節點,每個父節點下又包含 10 層子節點,在展示資料相同的情況下,比較 operamask-ui 與其他幾個主流 ui 架構産品的頁面加載時間、元件展示時間、 CPU 占用率等。

四、測試環境

被測對象:測試 Operamask-ui (以下檢查 om-ui ), easy-ui , extjs-ui , liger-ui 的 tree 元件,分别在 firefox 、 IE 、 chrome 三種浏覽器下的 render 、 domready 、 pageload 、元件内容完全展現的時間以及 CUP 使用率。

硬體配置: Pentium® Dual-Core CPU E5300 @2.60GHz 2.60GHz , 3.24GB 記憶體

軟體名稱 版本
FireFox 7.0.1
IE IE8
Chrome 17.0
ProcessExplorer 14.12

五、測試案例

1、被測元件案例

按照各個 ui 架構構造 tree 元件的方式,分别建立 tree 測試元件,測試頁面中僅放置一個被測 tree , tree 展現格式為 10*10 ( 10 個父節點,每個父節點中疊代 10 層子節點)。

2、監控參數案例

(1)       Render Time

var time_to_page_start = new Date()*1,bodyHeights = [];
(function(){
		function handleRender(){
			window.pmc_start_render_time = new Date()*1 - time_to_page_start;
			var h = document.createElement('h3');
			h.innerHTML='Time To Start Render:'+window.pmc_start_render_time + ' ms';
			document.body.appendChild(h);
		}
		if(document.body && document.body.offsetHeight > 0 ){ 
			handleRender();
			return;
		}
		if(document.body){
			bodyHeights.push(document.body.offsetHeight);
		}
		setTimeout(arguments.callee,30);
})();
      

說明:首先記錄開始時間 time_to_page_start ,監控 document.body.offsetHeight ,當大于 0 時,表明使用者能看到頁面上的内容的時間,用次時間減去開始時間,則為渲染時間。

(2)       Dom Ready

Dom Ready 為頁面内所有 dom 節點加載完成的時間。 FireFox 中增加了一個 DOMContentLoaded 方法,該方法是在頁面的 DOM 内容加載完成後即觸發,而無需等待其他資源的加載。 Webkit 引擎從版本 525 ( Webkit nightly 1/2008:525+ )開始也引入了該事件, Opera 中也包含該方法。 IE 不支援該方法,但是在 IE 下, dom 的某些方法隻有在 dom 解析完成後才能調用, doScroll 就是這樣一種方法,是以我們通過監控 doScroll 來監控 IE 中的 Dom   Ready 時間。 Webkit 引擎低版本通過監控 readyState 來判斷 dom 是否加載完畢。 JS 腳本如下:

var time_to_page_start = new Date()*1;
(function(){
	function domreadyTime(){
	    window.pmc_start_render_time = new Date()*1 - time_to_page_start;
		var h = document.createElement('h3');
		h.innerHTML = 'Time To Dom Ready: ' + window.pmc_start_render_time + ' ms';
		document.body.appendChild(h);
    }
    this.conf = {enableMozDOMReady:true};   
    var isReady = false;   
    function doReady(){   
        if( isReady ) return;   
        isReady = true;   
        domreadyTime();   
    }   
    if( /MSIE/.test(navigator.userAgent) ){   
      (function(){   
       if ( isReady ) return;   
       try {   
          document.documentElement.doScroll("left");   
       } catch( error ) {   
          setTimeout( arguments.callee, 0 );   
          return;   
       }   
       doReady();   
     })();   
    window.attachEvent('onload',doReady);   
  }   
  else if (/Chrome/.test(navigator.userAgent)){   
    (function(){   
      if( isReady ) return;   
      if (/loaded|complete/.test(document.readyState))   
         doReady();   
      else  
         setTimeout( arguments.callee, 0 );   
     })();   
    window.addEventListener('load',doReady,false);   
  }   
  else{   
     if( /Firefox/.test(navigator.userAgent) || this.conf.enableMozDOMReady)   
       document.addEventListener( "DOMContentLoaded", function(){   
       document.removeEventListener( "DOMContentLoaded", arguments.callee, false );   
       doReady();   
     }, false );   
     window.addEventListener('load',doReady,false);   
   }   
})();
      

(3)       Page Load

Page Load 時間指的就是 window.onload 事件觸發的時間。與 DOM Ready 時間相比, Page Load 的時間往往要更靠後一些,因為 Page Load 不僅僅是 HTML 文檔解析完畢還包括了所有資源加載所需要的時間,例如圖檔資源的加載、 iframe 的加載等。 JS 腳本如下:

var time_to_page_start = new Date()*1;
(function(){
	function pageLoad(){
	    window.pmc_start_render_time = new Date()*1 - time_to_page_start;
		var h2 = document.createElement('h3');
		h2.innerHTML = 'Time To Page Load: ' + window.pmc_start_render_time + ' ms';
		document.body.appendChild(h2);
	}
//判斷浏覽器是否能夠識别window.addEventListener,假如可以,則執行以下代碼
	if(typeof window.addEventListener!="undefined"){  
		window.addEventListener('load',function(){
			window.removeEventListener('load', arguments.callee, false);
			pageLoad();
		},false);
	}
//某些浏覽器無法識别window.addEventListener,隻能識别document.addEventListener,是以要增加這一步判斷
	else if(typeof document.addEventListener!="undefined"){     
		document.addEventListener("onload",function(){
			document.removeEventListener('onload', arguments.callee, false);
			pageLoad();
		},false);
	}
	//前面兩種都無法識别,則判定是否可以識别window.attachEvent  (IE)
	else if(typeof window.attachEvent!="undefined"){
		window.attachEvent("onload",function(){
			pageLoad();
		});
	}
	//前三種都無法識别,則用這最後一種:老式鍊式事件處理方式
	else{
		var oldfn = window.onload;
		if(typeof window.onload!="function"){
			window.onload = function(){
				pageLoad();
			}
		}
		else{
			window.onload = function(){
				oldfn();
				pageLoad();
			}
		}
})();
      

(4)       Show Time

在我們的測試案例中,令 grid 元件讀取 500 條資料, tree 元件展示 10 個節點,每個節點中包含 10 層子節點(即子節點中又包含 1 個子節點,如此循環 10 層), Show Time 用于監控元件在頁面中所有資料完全展現出來的時間,通過在頁面中查找 grid 元件的最後一條資料來判斷該元件内容是否完全展現,通過在頁面中查找 tree 元件的最後一個節點來判斷該元件内容是否完全展現。 JS 腳本如下:

var time_to_page_start = new Date()*1;
/*<![CDATA[*/
(function(){
	function handleRender(){
		window.pmc_start_render_time = new Date()*1 - time_to_page_start;
		var h = document.createElement('h3');
		h.innerHTML = 'Time To Start show: ' + window.pmc_start_render_time + ' ms';
			document.body.appendChild(h);
	}
	//if($('table').find('tr').eq(500).length > 0){  //grid查找方法
	//if($('ul li').length == 110){  //easy-tree,liger-tree,om-tree查找方法
	if($('table tr').length == 111){   //extjs-tree查找方法
		handleRender();
		return;
	}
	setTimeout(arguments.callee,30);
})();
      

 3、測試執行

為了避免各個監控參數互相影響,在被測元件的 html 檔案中每次隻添加一個監控參數的 js 檔案,測試 CPU 時不添加監控參數的 js 檔案。測試時隻有一種浏覽器被打開。

測試各個監控參數的操作步驟為:在浏覽器中輸入對應元件的 URL ,回車,記錄頁面中顯示的時間,重複此步驟 10 次,取平均值。為了保證不受浏覽器緩存的影響,保證監控參數的監聽正确,每次執行完之後要清空緩存,重新開機浏覽器。

測試 CPU 占用率的操作:打開 ProcessExplorer ,打開浏覽器,輸入 URL ,回車,記錄回車後測試浏覽器在 ProcessExplorer 中的最大值。

六、測試資料和圖表

extjs-tree 在 firefox 下的特别說明:

按照我們的測試案例,設定 tree 元件為 10*10 時( 10 個父節點,每個父節點循環 10 層子節點), extjs 的 tree 元件在 FireFox7.0.1 中無法正常顯示,在 IE8 和 Chrome 下可以正常顯示,是以在測試 firefox 時,我們修改了 tree 元件的節點,使其展示 9*11 層。在 tree 元件為 10*10 時,節點個數為 10*10+10=110 個, tree 元件為 9*11 時,節點個數為 9*11+9=108 個,是以 extjs 的 tree 元件在 firefox 下測出的資料不是特别準,比正确的資料偏小,但是與 110 個總個數相比, 2 個節點的時間幾乎可以忽略。

6.1 Render Time

機關ms

FireFox7.0.1 IE8 Chrome17.0
om- tree 166 344 108
easy- tree 229 997 251
extjs- tree 59 671 222
liger- tree 120 280 109

operamasks-ui和其它js架構性能對比
operamasks-ui和其它js架構性能對比

6.2 Dom Ready

機關ms

FireFox7.0.1 IE8 Chrome17.0
om- tree 4 31 7
easy- tree 6 31 5
extjs- tree 9 31 9
liger- tree 6 33 29

operamasks-ui和其它js架構性能對比
operamasks-ui和其它js架構性能對比

6.3 Page Load

機關ms

FireFox7.0.1 IE8 Chrome17.0
om- tree 7 32 7
easy- tree 11 31 5
extjs- tree 13 31 9
liger- tree 15 35 29

operamasks-ui和其它js架構性能對比
operamasks-ui和其它js架構性能對比

6.4 show time

機關ms

FireFox7.0.1 IE8 Chrome17.0
om- tree 84 359 99
easy- tree 179 984 263
extjs- tree 506 1145 365
liger- tree 114 281 82

operamasks-ui和其它js架構性能對比
operamasks-ui和其它js架構性能對比

6.5 CPU

FireFox7.0.1 IE8 Chrome17.0
om-tree 19.54 28.92 15.63
easy- tree 36.17 38.30 28.92
extjs- tree 50.03 52.37 38.48
liger- tree 22.32 28.92 17.31

operamasks-ui和其它js架構性能對比
operamasks-ui和其它js架構性能對比

總的來說,各個元件在ie8下面表現最差,chrome和火狐各有千秋

ext性能表現比較好,這也是我們開始沒有想到的,其實ext性能不差,隻是功能太多了,拖累了,在功能平等的情況下性能還是不錯的。

還有就是我們測試都是本地資源,是以資源加載時間可以忽略,其實資源大小擺在那裡,哪個js庫大哪個小也無需我們列出來,況且功能

不同資源大小肯定不同,如果糾結于資源大小是不公平的。