優化Ajax開發的最佳實踐,有助於編寫更加高效且健壯的Ajax代碼。
(1)最小化調用
最小化調用數量的方法之一是將大量調用合併成少量調用。如果數據量相對較小,那麼在大多數網絡中,主要問題就在於延遲。延遲是瀏覽器真正獲取服務器之間的連接所需的時間,有時它會佔去大部分連接時間。用戶所感受到的總延遲由幾個部分組成,包括瀏覽器的緩存設置、DNS客戶端,以及物理連接。
沒有簡易公式或代碼片段供我們來瞭解如何減少Web應用程序調用。然而,只需一個簡單的練習,就可以演示如何對從客戶端到服務器的Ajax調用數量進行控制。考慮下面購買二手摩托車的Web應用程序。
首先,選擇摩托車的年份,然後選擇摩托車的構造,最後選擇摩托車的型號。自始至終,Ajax一直在後台運行,更新Web應用程序中的下拉框來為用戶過濾清單,以方便用戶選擇。
要開始這一練習,首先要為客戶端及服務器創建一個簡單圖表(有一個文本框),然後為瀏覽器進行的Ajax調用畫線,以從服務器獲取用戶數據。
可將對品牌和型號進行的調用合併到一個調用中,從而實現優化設計。不是對品牌進行一次調用,然後針對型號進行另一次調用,而是對型號進行緩存,這樣,當用戶選擇品牌時,新代碼只檢索緩存中可用的型號列表。從本地緩存中獲取數據要比從服務器獲取相同數據快得多。迴避額外的服務調用,避免服務調用的延遲。
新設計在瀏覽器與服務器之間的通信中去掉了一個調用。可利用下面代碼進一步減少調用數量,其中的一些關鍵行可用於存儲在數組中檢索到的數據,供以後查找使用。
var choices=new Array;
function fillChoiceBoxes(year){
if(dojo.indexOf(choices,year)==-1){
//開始
}else{
choices[year]=result;
//Ajax調用結果
}
//調用函數
fillSelect(dojo.byId(\'makes\'),choices[year]);
}
在反覆考慮兩個不同的型號時,Web應用程序會使用本地緩存數據,而不是發起附加服務調用。僅緩存靜態數據,至少在用戶會話持續階段是這樣的。不要因為緩存了不應緩存的數據,而引起一系列問題。通過減少客戶端與服務器之間的交互次數,以及在可能的情況下緩存數據,可以最小化調用次數。
(2)讓數組變得很小
為提高數據處理性能,需要讓服務器與客戶端之間傳輸的數據盡量的小。為了高效地完成這一任務,必須控制從服務層到能夠指定從服務器到客戶端的消息類型的部分。有充足的理由證明,XML適合作為客戶端到服務器的通用消息格式。理由之一是存在足夠多的庫或框架用於XML序列化。
然而,當與JSON對比時,XML顯得很冗長,JSON則更加簡明。目前已經有很多可以將消息方便地構建成JSON格式的庫,這樣就可以通過JSON的方式將數據從服務端傳送到客戶端。
如果服務器響應使用JSON,那麼可通過提供一個參數來使用相同的客戶端對象。仔細研究下面代碼,其展示了使用XML的摩托車對象的表示。
<motorcycle>
<year>2012</year>
<make>Moto</make>
<model>Uberfast</model>
</motorcycle>
下面代碼展示了使用JSON的摩托車對象。注意,它的代碼量減少了大約25%(如果去掉空格)。
{\"motorcycle\":{
\"year\":\"2012\",
\"make\":\"Moto\",
\"model\":\"Uberfast\"
}
}
數據量變小了,不但從服務端到客戶端的傳輸時間減少了,而且字符串的減小還節省瞭解析時間。在設計需要傳輸的數據時,其所包含的字符越少越好。
(3)預加載組件
可通過在Ajax調用中加載JavaScript文件與圖像之類的組件來充分利用瀏覽器的緩存。需要注意的是,預加載JavaScript文件和圖像,僅對那些開啟緩存功能的用戶有益,不過大多數用戶的瀏覽器都開啟了緩存功能。
要預加載外部JavaScript文件,可以將JavaScript文件包含在頁面中,但是,只有當該頁面很小且僅想優化少量資源時,才適合採用這一方式。例如,對於一個將工作流引入用戶的相對輕量級的頁面,預加載非常有用。考慮介紹最小化調用時的購買摩托車的例子,可在流的早期頁面中預加載用於包含下拉框的頁面的、包含全部Ajax代碼的JavaScript代碼。
在使用Ajax調用的方法更新圖片時,預加載圖像會提供很大便利。在預加載圖像後,當用戶將鼠標移動到元素時、從下拉框中進行選擇時,或者單擊按鈕時,不必等待瀏覽器對圖像進行檢索。即使Ajax以異步方式發生,也需要花費一些時間將圖像從服務器傳送到客戶端,並且圖像在全部下載完畢之前不會在客戶端中顯示。例如,在下面示例中,當用戶進行從清單中選擇摩托車這一操作時,所採用的圖像就是使用標準JavaScript代碼預加載的。
<html>
<head><title></title></head>
<body>
<script type=\"text/Javascript\"language=\"Javascript\">
var img=new Image;
img.src="https://mysite/motocool.jpg";
</script>
</body>
</html>
在為頁面預加載圖像時,JavaScript的位置很重要,當然不希望因為在HTML中加入了JavaScript代碼而影響頁面的加載速度。一般的規則是,可將<script>元素當中的JavaScript代碼放到HTML頁面的最後部分,因為在考慮可同時下載多少資源時會發現瀏覽器的能力相對有限。如果可能,將腳本加到HTML頁面的最後部分,從而幫助瀏覽器更快速地加載圖像和其他資源。
在HTML 5中,可使用<script>標記的新async屬性。這將告訴瀏覽器可以異步運行JavaScript代碼,這樣,JavaScript代碼可以在頁面中運行其他東西時執行。
(4)輕鬆處理錯誤
在JavaScript代碼中定義的每個函數,都要假設會有惡意輸入發生,因為防禦性能強的代碼比使用try catch語句所編寫的代碼更善於處理錯誤。例如,想使用JavaScript函數來根據用戶輸入進行計算,要在計算前檢查輸入。
function caculateDistance(source,dest){
if(!isNaN(source)||!isNaN(dest)){
dojo.byId(\"errors\").innerHTML=\"提示錯誤\";
}
}
即使代碼具有防禦能力,在適當的時候,也可使用try catch語句與錯誤回調。在下面示例中,JavaScript使用try catch語句來捕獲錯誤。
function calculateDistance(source,dest){
try{
//執行計算...
}catch(error){
dojo.byId(\"errors\").innerHTML=\"提示錯誤\";
}
}
下面示例演示的是在調用Dojo Toolkit中所提供的xhrGet方法時對錯誤回調的使用。錯誤參數是可選的,因此可以很容易地跳過錯誤處理器的定義。
var args={
url:\"/js/dojo//NoSuchFile\",
handleAs:\"text\",
preventCache:true,
load:function(data){
//當加載成功時,執行計算
},
error:function(error){
dojo.byId(\"errors\").innerHTML=\"提示錯誤\";
}
}
var ajx=dojo.xhrGet(args);
如何處理頁面上的錯誤,這既是個業務問題,又是個技術問題。適當的時候,客戶能夠提供在出現異常時有效的默認處理方式。
最後,不要在JavaScript提示對話框中顯示錯誤描述。用戶不是軟件工程師,因此,這類提示信息對於用戶來說沒有任何意義。除了不要為用戶提供無意義的信息之外,還要在提示對話框中要求客戶取消該對話框,以返回頁面。
function calculateDistance(source,dest){
try{
//執行計算
}catch(error){
//不要:
//alert(error.message);
//最好:
dojo.byId(\"errors\").innerHTML=\"提示錯誤\";
}
}
(5)使用現有工具
通過使用現有工具(框架與平台),可有效利用相應資源。大多數成熟的技術人員,會使用已在多個平台上測試過的,具有跨瀏覽器兼容性的工具。現有工具的大部分特性可用於部署到自己的項目中。
很多現有的優秀工具,除了支持Ajax調用之外,還能支持很多其他函數與特性,如動畫等。jQuery是比較優秀的JavaScript庫,它能提供全套的Ajax功能。jQuery還支持不同的消息格式及其他基於Ajax的方法,如getScript,它可用於下載並執行JavaScript文件,是預載組件最佳實踐的起源。