讀古今文學網 > 編寫高質量代碼:改善JavaScript程序的188個建議 > 建議150:優化Ajax開發的最佳實踐 >

建議150:優化Ajax開發的最佳實踐

優化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文件,是預載組件最佳實踐的起源。