本文所介紹的 5 個最佳實踐,可以應用到您 web 應用程序 Ajax 開發工作中:
這些最佳實踐,有助於您編寫更加健壯的 JavaScript 代碼,並使您的 Ajax 代碼執行的更快,這可以給用戶帶來益處。
Ajax 用於描述存在已久的技術:JavaScript 代碼、XML、以及能夠通過 HTTP 進行異步調用的對象。Ajax 常用於避免提交併重新加載整個網頁,特別是在用戶執行的動作不需要重新加載整個網頁時。
在過去幾年中,支持 Ajax 的站點在不斷的完善,作爲此類站點的開發工具,Ajax 的應用也越來越廣泛。使用本文的實踐通過 Ajax 和 JavaScript 來構建更優的 web 應用程序。
聽起來可能很明顯,但使用 Ajax 技術提高您的 web 應用程序性能,惟一能做的就是最小化您的調用數量。
最小化調用數量的方法之一是將大量調用合併成少量調用。如果數據量相對小(見 “讓數據變小”),那麼在大多數網絡中,主要問題就在於延遲。延遲是瀏覽器真正獲取服務器與服務的連接所需的時間,有時它會佔去大部分連接時間。用戶所感受到的總延遲由幾個部分組成,包括瀏覽器的緩存設置、DNS 客戶端、以及物理連接。
沒有簡易公式或代碼片段供您閱讀來了解如何減小 web 應用程序調用。然而,只需一個簡單的練習,就可以演示如何對從客戶端到服務器的 Ajax 調用數量進行控制。考慮購買二手摩托車的 web 應用程序(見圖 1)。
圖 1. 搜索二手摩托車的示例 web 頁面
首先,用戶選擇摩托車的年份。然後,用戶選擇摩托車的構造。最後用戶選擇摩托車的型號。從始至終,Ajax 一直在後臺運行,更新 web 應用程序中的下拉框來爲用戶過濾清單,以方便用戶選擇。
要開始這一練習,首先要爲客戶端及服務器創建一個簡單圖表(有一個文本框)。然後爲您瀏覽器進行的 Ajax 調用畫線,來從服務器獲取用戶數據,如圖 2 所示。
圖 2. 繪製 Ajax 調用
可通過將對品牌和型號進行的調用合併到一個調用中,來優化設計。不是對品牌進行一次調用,然後針對型號進行另一次調用,而是對型號進行緩存,這樣,當用戶選擇品牌時,新代碼只檢索緩存中可用的型號列表。從本地緩存中獲取數據要比從服務獲取相同數據快得多。迴避額外的服務調用,您就可以避免服務調用的延遲。新的通信情況如圖 3 所示。
圖 3. 合併獲取品牌調用與獲取型號調用後的 Ajax 調用
到目前爲止,新設計在瀏覽器與服務器之間的通信中去掉了一個調用。您可利用清單 1 中的代碼進一步減少調用數量,其中的一些關鍵行可用於存儲在數組中檢索到的數據,供以後查找使用。
清單 1. 在緩存中存儲本地數據
var choices = new Array(); function fillChoiceBoxes(year) { // see resources for links to dojo toolkit... if (dojo.indexOf(choices, year) == -1) { // go get the } else { // make the ajax call and fill the choices. choices[year] = result; // result of ajax call. } // calling a function to fill the values... fillSelect(dojo.byId('makes'), choices[year]); } |
如果用戶在反覆考慮兩個不同的型號,web 應用程序會使用本地緩存數據,而不是發起附加服務調用。僅緩存靜態數據 —— 至少是在用戶會話持續階段。不要因爲緩存了不應緩存的數據,而引起一系列問題。
正如本例所展示的,可通過減少客戶端與服務器之間的交互次數,以及在可能的情況下緩存數據,來最小化調用。
爲提高數據處理性能,需要讓服務器與客戶端之間出傳輸的數據儘量的小。爲高效地完成這一任務,必須已經控制了從服務層,到能夠指定從服務到客戶端的消息類型的部分。
有充足的理由證明,XML 適合作爲客戶端到服務器的通用消息格式。理由之一是存在足夠多的庫或者框架,來用於 XML 序列化。
然而,當與 JavaScript Serialized Object Notation(JSON)對比時,XML 顯得很冗長,而前者更加簡明。目前已經有很多可以將您的消息方便地構建成 JSON 格式的庫,這樣就可以通過 JSON 的方式將數據從服務端傳送的客戶端。
很多客戶端庫,比如 Dojo Toolkit,允許定義服務所採用的傳輸格式。如果服務響應使用 JSON,可通過提供一個參數來使用相同的客戶端對象。
仔細研究一下清單 2 中的代碼,其展示了使用 XML 的摩托車對象的表示。
清單 2. 使用 XML 的摩托車數據
<motorcycle> <year>2010</year> <make>Motocool</make> <model>Uberfast</model> </motorcycle> |
現在來看一下清單 3,其展示了使用 JSON 的相同數據。注意,它的代碼量減少了大約 25%(如果去掉空格)。
清單 3. 使用 JSON 的摩托車數據
{ "motorcycle" : { "year" : "2010", "make" : "Motocool", "model" : "Uberfast" } } |
由於數據量變小了,不僅減少了從服務端到客戶端的傳輸時間,而且,由於字符串的減小還節省了解析時間。
在設計需要傳輸的數據時,其所包含的字符越少越好。
可通過在 Ajax 調用中加載 JavaScript 文件與圖像之類的組件,來充分利用瀏覽器的緩存。需要注意的是,預加載 JavaScript 文件和圖像,僅對那些開啓緩存功能的用戶有益,不過大多數用戶的瀏覽器都開啓了緩存功能。
想要預加載外部 JavaScript 文件,將 JavaScript 文件包面中,但是,只有當該頁面很小而且僅想優化少量資源時,才適合採用這一方式。例如,當您有一個將工作流引入用戶的相對輕量級的頁面時,預加載非常有用。考慮 最小化調用 部分中購買摩托車的例子。可在流的早期頁面中預加載用於包含下拉框的頁面的、包含全部 Ajax 代碼的 JavaScript 代碼。
如果要用 Ajax 調用的方法更新圖片,預加載圖像會提供很大方便。預加載圖像後,當用戶將鼠標移動到元素時、從下拉框中進行選擇時、或者單擊按鈕時,不必等待瀏覽器對圖像進行檢索。即使 Ajax 以異步方式發生,也需要花費一些時間將圖像從服務器傳送到客戶端,並且在圖像全部下載完畢之前,它不會在客戶端中顯示。
在清單 4 所展示的例子中,用戶進行從清單中選擇摩托車這一操作時,所採用的圖像就是使用標準 JavaScript 代碼預加載的。
清單 4. 使用標準 JavaScript 代碼預加載圖像
<html> <head><title>Preload example</title></head> <body> <!-- web page... --> <script type="text/javascript" language="javascript"> var img = new Image(); img.src = "http://path/to/motocool.jpg"; </script> </body> </html> |
爲頁面預加載圖像時,JavaScript 的位置很重要。您一定不希望因爲在 HTML 中加入了 JavaScript 代碼而影響頁面的加載速度。一般的規則是,可將
<script>
元素當中的 JavaScript 代碼放到 HTML 頁面的最後部分,因爲在考慮可同時下載多少資源時,瀏覽器的能力就相對有限了。如果可能,將腳本加到 HTML 頁面的最後部分,來幫助瀏覽器更快速加載圖像和其他資源。
在 HTML 5 中,可使用 <script>
標記的新 async
屬性。這將告訴瀏覽器異步運行 JavaScript 代碼,這樣,它可以在頁面中運行其他東西時執行。
在 JavaScript 代碼中定義的每個函數,都要假設會有惡意輸入發生,因爲,防禦性能強的代碼比使用 try... catch
語句所編寫的代碼更善於處理錯誤。例如,如果想使用 JavaScript 函數來根據用戶輸入進行計算,在計算前檢查輸入,如清單 5 所示。
清單 5. 檢查用戶輸入
function caculateDistance(source,dest) { if (! isNaN(source) || ! isNan(dest)) { dojo.byId("errors").innerHTML = "Please provide a valid number."; } } |
即使代碼具有防禦能力,在適當時候,也可使用 try... catch
語句與錯誤回調。清單 6 演示了在 JavaScript 代碼中使用
try... catch
語句來捕獲錯誤。
清單 6. 使用
try... catch
語句來處理錯誤
function calculateDistance(source,dest) { try { // do some calculations... } catch (error) { dojo.byId("errors").innerHTML = "An error occurred while adding the numbers"; } } |
清單 7 演示了在調用 Dojo Toolkit 中所提供的 xhrGet()
方法時,對錯誤回調的使用。錯誤參數是可選的,因此可以很容易地跳過錯誤處理器的定義。
清單 7. 使用具有
xhrGet()
的錯誤回調
var args = { url: "/moin_static185/js/dojo/trunk/dojo/../dojo/NoSuchFile", handleAs: "text", preventCache: true, load: function(data) { // do something when successful... }, error: function(error) { dojo.byId("errors").innerHTML = "An error occurred while getting the data.."; } } var ajx = dojo.xhrGet(args); |
如何處理頁面上的錯誤,這既是個業務問題,也是個技術問題。要詢問客戶,在出現問題時,想讓用戶看到什麼消息,因爲任何展示給用戶的消息,都會對業務造成影響。適當時,客戶能夠幫助提供在出現異常時有效的默認處理方式。
最後,不要象清單 8 中那樣,在 JavaScript 提示對話框中顯示錯誤描述。您的用戶不是軟件工程師,因此,這類提示信息對於用戶來說沒有任何意義。除了不要爲用戶提供無意義的信息之外,提示對話框應當要求客戶取消該對話框,來返回 web 頁面。
清單 8. 在錯誤處理中避免 JavaScript 提示對話框
function calculateDistance(source,dest) { try { // do some calculations... } catch (error) { // Bad: // alert(error.message); // Better: dojo.byId("errors").innerHTML = "An error occurred while calculating data..."; } } |
最後,作爲最佳實踐之一,要儘量避免 Not Invented Here(NIH)綜合症。通過使用現有工具(框架與平臺),可有效利用其資源。大多數成熟的技術人員,會使用已在多個平臺上測試過,並具有跨瀏覽器兼容性的工具。現有工具的大部分特性可用於部署到您自己的項目中。
很多現有的優秀工具,除了能提供 Ajax 調用之外,還能支持很多其他函數與特性,比如動畫。表 1 中列出了其中一些工具。
表 1. 爲 Ajax 調用提供方法的 JavaScript 工具
工具 | 描述 |
---|---|
Dojo Toolkit | Dojo Toolkit 是免費的 JavaScript 工具套件。它爲一般 web 頁面提供 Ajax 調用方法,以及 Representational State Transfer(REST)服務。Dojo Toolkit 方法支持 XML、JSON、以及明文的消息格式。 |
Google Web Toolkit(GWT)Designer | Google 最近收購了 Instantiations Developer Tools 並重新推出一系列免費產品。其中之一是 GWT Designer,可將其安裝到現有的 Eclipse 中。可利用設計器來輔助構建採用 GWT 的接口。GWT 用於構建採用 Ajax 的複雜 web 應用程序,這使得 web 應用程序可以如同本地應用程序一樣複雜。與 Rich Ajax Platform(RAP)類似,GWT 不單單是一個 JavaScript 框架,而且還是編譯到 Ajax-enabled HTML 中的基於 Java™ 的工具集。 |
jQuery | jQuery 是另一個 JavaScript 庫,它能提供全套的 Ajax 功能。jQuery 還支持不同的消息格式以及其他基於 Ajax 的方法,比如
getScript() ,它可用於下載並執行 JavaScript 文件(是
預載組件 最佳實踐的起源)。 |
Prototype | Prototype 也是個 JavaScript 框架,可用於方便地發起 Ajax 調用。利用 Ajax.PeriodicalUpdater 之類的方法,可基於策略來更新 Ajax 頁面中的值,這樣,就可爲運行時間較長的服務進程實現進度條或者其他方式的控制。 |
Rich Ajax Platform (RAP) |
與表中列出的其他框架不同,RAP 是個完整的平臺,使得您可以利用 Eclipse 集成開發環境(IDE)和 Java(不是腳本)代碼來構建 Ajax-enabled 的更優站點。類似於構建一個 Swing 或者 Standard Widget Toolkit(SWT)應用程序。對於不想使用複雜的 HTML、CSS、以及 JavaScript 代碼的 Java 程序員來說,RAP 之類的平臺工具是非常不錯的選擇。 RAP 文檔提示說不要將其作爲插件安裝到現有 Eclipse 中。然而,可從 Eclipse 站點(見 參考資料)下載 Eclipse for Rich Client Platform(RCP)and RAP Developers 包,並將其安裝到單獨的位置。相關備忘單展示瞭如果導入示例項目。 |
在 web 應用程序中使用 Ajax ,可爲您的用戶提供整潔的 web 應用程序界面。Ajax 已對整個 HTML 頁面的傳遞提供了一些優化,然而,通過了解本文中描述的最佳實踐,可幫助您構建更加優化的 Ajax 應用程序。