改善 Dojo 應用程序的初始下載時間

    加載 Ajax 應用程序之後,隨後它將獲取較小的數據和內容片段,以避免重新呈現整個頁面的開銷,從而提高性能。這樣做的代價是,應用程序的初始下載時間通常會較長。本文將討論如何減少 Dojo 應用程序的初始下載時間並同時獲得很好的性能。

 

僅獲取所需的數據

    Asynchronous JavaScript and XML (Ajax) 應用程序能夠提高某些 Web 應用程序的性能。加載應用程序之後,獲取較小的數據和內容片段可以幫助避免重新呈現整個頁面的開銷。不過,這樣做得的代價是,應用程序的初始下載時間通常 會比較長。

    我現在已有多年的 Dojo 應用程序使用經驗。IBM® WebSphere® Application Server Feature Pack for Web 2.0Project Zero 現在都包括 Dojo Toolkit 的 IBM 分發版本,提供了一些增值擴展。由於 Dojo Toolkit 的模塊化特性,初始加載可能會花費相當長的時間,因爲使用的每個模塊可能都需要下載一些 JavaScript™、HTML 和 CSS 文件。這會在網絡上帶來大量額外的 IO 操作,遠遠超過每個模塊本身的大小。

    通常,這個模塊化特徵是程序員所必需的,因爲通過其可以方便地進行調試和編碼,但編寫了應用程序之後,此模塊化特徵就不再重要了——或不再需要了。您可以通過多種方法減少 Dojo 應用程序的初始下載時間。

 

使用 Dojo 構建和打包系統

    Dojo Toolkit 提供了打包和壓縮技術,用於將在應用程序中使用的 Dojo 代碼打包爲單個文件,然後使用名爲 Dojo ShrinkSafe 的壓縮技術將其壓縮到最小尺寸。大部分 Dojo 應用程序都應該將此技術作爲其部署的一部分使用,因爲此技術將極大地提高應用程序的性能(特別是初始下載時間)。您只需要爲應用程序創建概要,並在其中指 定要使用哪個 Dojo 組件。清單 1 顯示了一個示例。

    清單 1. 示例概要

 

dependencies ={

    layers:  [
        {
        name: "example.js",
        dependencies: [
			
			"dojo.*",
			"dojo.parser",
			"dijit.dijit",
			"dijit.Declaration",
			"dijit.layout.LayoutContainer",
			"dojox.layout.ContentPane",
			"dijit.Toolbar",
			"dijit.layout.AccordionContainer",
			"my.widget.Super"         
       	]
        }
    ],
	
	
    prefixes: [
        
		[ "dijit", "../dijit" ],
		[ "my", "/myWidgets"],
		[ "dojox", "../dojox" ]
    ]

};

     然後您將運行命令行構建工具,使用各種選項傳入概要。Dojo 構建然後將應用程序所需的所有代碼(包括 JavaScript、HTML 和 CSS)放入單個文件中,並對其進行壓縮。通過使用此方法,我發現在應用程序初始下載中,IO 調用的數量可能從 200 個以上減少到 2 個或 3 個。我還發現總體大小減少了約 60%。將很快推出關於使用 Dojo 構建和打包系統的 developerWorks 教程,不過在 Dojo 網站 上提供了關於打包系統和自定義構建的更多信息。

 

延遲加載和緩存 Dojo 內容

可 以極大減少初始下載大小的另一個方法是,對頁面的內容部分進行延遲加載,並在加載之後對其進行緩存。有時候,這樣的做法會更好:不在首次訪問應用程序時就 加載所需的所有東西,而僅在這個時候加載應用程序的部分內容。用戶完全可能會在訪問站點時從來不會訪問 Web 應用程序的某些特定部分,因此下載這些不會接觸的部分所消耗的時間都浪費掉了。所以,您並不需要下載應用程序中可能不會使用的部分。而且,第一印象極爲重 要:如果不能快速顯示初始主頁,可能會讓用戶更快放棄使用您的程序。

通常,您會希望加載包含初始菜單的佈局,然後在加載之後獲取主頁內容。常見 Dojo 應用程序通常由一些佈局元素組成。請看清單 2:


清單 2. 佈局

 

<body class="tundra">
	<div dojoType="dijit.layout.LayoutContainer" 
		layoutChildPriority="top-bottom" 
		id="main" 
		class="layout" >
		<div dojoType="dijit.layout.ContentPane" 
			layoutAlign="top" class="banner">
			<h2>Electronic and Movie Depot !!</h2>
		</div>
		<div dojoType="dijit.layout.ContentPane" 
			layoutAlign="top" class="menu">
			<div dojoType="dijit.Toolbar" id="mainMenuBar">
				<div dojoType="dijit.form.Button" 
					id="productListMenu" 
					οnclick="showItem('productList',
						'product/product.html');">
					Shopping
				</div>
				<div dojoType="dijit.form.Button" 
					id="orderListMenu" οnclick="showItem('orderPage',
						'cart/cart.html');">
					Shopping Cart
				</div>
			</div>
		</div>
		<div dojoType="dijit.layout.ContentPane" 
			class="mainArea" 
			id="center" layoutAlign="client">
			<div dojoType="dojox.layout.ContentPane" 
				executeScripts="true" id="productList" 
				style="display:none">
			</div>
			<div dojoType="dojox.layout.ContentPane" 
				executeScripts="true" 
				id="orderPage" 
				style="display:none">
			</div>
		</div>
	</div>
</body>
 

通過清單 2 可以瞭解一些事項。我創建了一個簡單的方法來將 HTML 片段加載到特定的內容中。我還使用 dojox.layout.ContentPane 替代了缺省 dijit。擴展的內容窗格允許在加載區域時執行 JavaScript。通過這樣,不僅可以延遲加載 HTML 內容,還可以採用延遲加載方式加載關聯的邏輯。清單 3 顯示了我所編寫的實用方法的實現。


清單 3. 延遲加載

 

var loaded = new dojox.collections.Dictionary();

function hideAll()
{
	console.debug("Hiding other content");
	var ids = loaded.getKeyList();
	console.debug("Getting ID -> " + ids);
	console.debug("List is Array");
	for (var id in ids) {
		console.debug("Getting section -> " + ids[id]);
		var section = dijit.byId(ids[id]);
		console.debug("Got Section -> " + section);
		if (section) {
			console.debug("setting DOM");
			section.domNode.style.display = "none";
		}
	}
	console.debug("Content is hid");
}

function showItem(key,template)
{
	hideAll();
	console.debug("Show Item -> " + key);
	var item = dijit.byId(key);	
	console.debug(item);
	if (item) 
	{
		if(!loaded.contains(key))
		{
			item.setHref(template);
			item.refresh();
			loaded.add(key,template);
		}
		
		item.domNode.style.display ="block";
	}
}

/**
 * Load Default page
 */
dojo.addOnLoad(function loadDefault()
{
	console.debug("Loading initial state");
	showItem('productList','product/product.html');
});
 

    在清單 3 中調用 showItem 時,我隱藏了在主體中可能可見的任何內容。我然後進行檢查,確定是否加載了 HTML。如果未加載,將下載模板,然後將其緩存在 Dojo 詞典中。下次請求此頁面時,將會直接顯示該區域。我還使用 dojo.addOnLoad 方法加載缺省頁面。

    在清單 3 中調用 showItem 時,我隱藏了在主體中可能可見的任何內容。我然後進行檢查,確定是否加載了 HTML。如果未加載,將下載模板,然後將其緩存在 Dojo 詞典中。下次請求此頁面時,將會直接顯示該區域。我還使用 dojo.addOnLoad 方法加載缺省頁面。

 

不要全部使用 dijit

我們很可能喜歡爲主要應用程序組件創建 dijit(Dojo 小部件)。例如,在清單 4 中,可以看到將應用程序處理爲 Dojo dijit 的示例。


清單 4. 將應用程序處理爲 dijit 可以減少下載時間

 

<div dojoAttachPoint = "registerId"
	dojoType="registration:RegistrationWidget" 
	style="display:none"
>
</div>
<div dojoAttachPoint = "datacenterId"
	dojoType="datacenters:DataCentersWidget"  
	inputTopic="no.show.datacenter" 
	style="display:none">
</div>
 

    在清單 4 中,我將每個應用程序組件都包裝在 dijit 中。反過來,每個 dijit 都由子 dijit 組成。甚至可以將加載整個應用程序視爲超 dijit:

<div id = "layout" dojoType="layout:EEFLayoutWidget" class="layoutDef"></div>

問題是,您忽略了延遲加載內容(或太過複雜而不能考慮這個選項),特別在構建中包括所有小部件的情況下。我發現,最好爲 UI 組件(Data Grid、專用組合框、特殊文本區)創建 dijit,然後加載使用 dijit 的普通 HTML 模板。

通過遵循一些指導原則和實踐,可以很容易地減少下載應用程序的時間,而且仍然能夠獲得 Dojo 具有的一些性能優勢。

 

參考資料

學習


獲得產品和技術


討論

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章