本人僅出于學(xué)習(xí)目的翻譯,完整無誤文章請(qǐng)參見原文!
面向Java開發(fā)者的Ajax:構(gòu)建動(dòng)態(tài)的Java應(yīng)用程序
Ajax鋪設(shè)了更好的開發(fā)Web應(yīng)用的道路
級(jí)別:中級(jí)
Philip McCarthy (mailto:philmccarthy@gmail.com?subject=Build dynamic Java applications), Software Development Consultant, Independent Consultant
9月20日2005年
頁面重載提出了一個(gè)在Web應(yīng)用開發(fā)中最大的可用性障礙,對(duì)于java開發(fā)來說也是一個(gè)重大的挑戰(zhàn)。在本系列中,作者Philip McCarthy介紹了通過后臺(tái)通道的方法來創(chuàng)建動(dòng)態(tài)Web應(yīng)用的經(jīng)驗(yàn)。Ajax(Asynchronous JavaScript and XML)是一個(gè)結(jié)合了Java技術(shù)、XML、以及JavaScript的編程技術(shù),可以讓你構(gòu)建基于Java技術(shù)的Web應(yīng)用,并打破了使用頁面重載的慣例。
Ajax,異步JavaScript與XML,是使用客戶端腳本與Web服務(wù)器交換數(shù)據(jù)的Web應(yīng)用開發(fā)方法。這樣,Web頁面不用打斷交互流程進(jìn)行重新加裁,就可以動(dòng)態(tài)地更新。使用Ajax,你可以創(chuàng)建接近本地桌面應(yīng)用的,直接的、高可用的、更豐富的、更動(dòng)態(tài)的Web用戶接口界面。
Ajax不是一個(gè)技術(shù),它更像是一個(gè)模式—標(biāo)志并描述有用的設(shè)計(jì)技巧的一種方法。對(duì)于剛了解它的許多開發(fā)人員來說,它是一種新的感覺,但是實(shí)現(xiàn)Ajax的所有組件都已存在了許多年。當(dāng)前的熱鬧是因?yàn)樵?/span>2004與2005年出現(xiàn)了一些基于Ajax的非常動(dòng)態(tài)的WebUI,尤其是Google的GMail與Maps應(yīng)用系統(tǒng)、與照片共享網(wǎng)站Flickr。這些UI充分地使用了后臺(tái)通道,也被一些開發(fā)者稱為“Web 2.0”,并導(dǎo)致了大家對(duì)Ajax應(yīng)用興趣的猛漲。
在本系列中,我將給出所有你需要的開發(fā)你自己的Ajax應(yīng)用的工具。在這第一篇文章中,我將解釋在Ajax背后的概念,示范為基于Web的應(yīng)用系統(tǒng)創(chuàng)建一個(gè)Ajax接口的基本步驟。我將使用示例代碼來示范實(shí)現(xiàn)Ajax動(dòng)態(tài)接口的服務(wù)器端Java代碼與客戶端JavaScript腳本。最后,我將指出一些Ajax方法中易犯的錯(cuò)誤,以及在創(chuàng)建Ajax應(yīng)用時(shí)應(yīng)該考慮的廣泛范圍內(nèi)的可用性與易訪問性方面的問題。
一個(gè)更好的購物車
你可以使用Ajax來加強(qiáng)傳統(tǒng)的Web應(yīng)用,通過消除頁面載入來使交互更流暢。為了示范它,我將使用一個(gè)簡(jiǎn)單的,能動(dòng)態(tài)更新加入的物品購物車。結(jié)合一個(gè)在線商店,這個(gè)方法可以不用等待點(diǎn)擊后的頁面重載,而讓我們繼續(xù)瀏覽并挑選物品到購物車中。雖然,本文中的代碼針對(duì)購物車?yán)?,但其中展示的技術(shù)可以用到其它的Ajax應(yīng)用中。列表1中展示了購物車示例所使用的HTML代碼。在整篇文章中,我都將會(huì)引用到這些HTML代碼。
列表1:購物車示例的相關(guān)代碼片斷
<!-- Table of products from store‘s catalog, one row per item -->
<th>Name</th> <th>Description</th> <th>Price</th> <th></th>
...
<tr>
<!-- Item details -->
<td>Hat</td> <td>Stylish bowler hat</td> <td>$19.99</td>
<td>
<!-- Click button to add item to cart via Ajax request -->
<button onclick="addToCart(‘hat001‘)">Add to Cart</button>
</td>
</tr>
...
<!-- Representation of shopping cart, updated asynchronously -->
<ul id="cart-contents">
<!-- List-items will be added here for each item in the cart -->
</ul>
<!-- Total cost of items in cart displayed inside span element -->
Total cost: <span id="total">$0.00</span>
Ajax處理過程
一個(gè)Ajax交互從一個(gè)稱為XMLHttpRequest的JavaScript對(duì)象開始。如同名字所暗示的,它允許一個(gè)客戶端腳本來執(zhí)行HTTP請(qǐng)求,并且將會(huì)解析一個(gè)XML格式的服務(wù)器響應(yīng)。Ajax處理過程中的第一步是創(chuàng)建一個(gè)XMLHttpRequest實(shí)例。使用HTTP方法(GET或POST)來處理請(qǐng)求,并將目標(biāo)URL設(shè)置到XMLHttpRequest對(duì)象上。
現(xiàn)在,記住Ajax如何首先處于異步處理狀態(tài)?當(dāng)你發(fā)送HTTP請(qǐng)求,你不希望瀏覽器掛起并等待服務(wù)器的響應(yīng),取而代之的是,你希望通過頁面繼續(xù)響應(yīng)用戶的界面交互,并在服務(wù)器響應(yīng)真正到達(dá)后處理它們。要完成它,你可以向XMLHttpRequest注冊(cè)一個(gè)回調(diào)函數(shù),并異步地派發(fā)XMLHttpRequest請(qǐng)求。控制權(quán)馬上就被返回到瀏覽器,當(dāng)服務(wù)器響應(yīng)到達(dá)時(shí),回調(diào)函數(shù)將會(huì)被調(diào)用。
在Java Web服務(wù)器上,到達(dá)的請(qǐng)求與任何其它HttpServletRequest一樣。在解析請(qǐng)求參數(shù)后,servlet執(zhí)行必需的應(yīng)用邏輯,將響應(yīng)序列化到XML中,并將它寫回HttpServletResponse。
回到客戶端,注冊(cè)在XMLHttpRequest上的回調(diào)函數(shù)現(xiàn)在會(huì)被調(diào)用來處理由服務(wù)器返回的XML文檔。最后,通過更新用戶界面來響應(yīng)服務(wù)器傳輸過來數(shù)據(jù),使用JavaScript來操縱頁面的HTML DOM。圖1是Ajax處理過程的一個(gè)時(shí)序圖。
圖1:Ajax處理過程
現(xiàn)在,你應(yīng)該對(duì)Ajax處理過程有了一個(gè)高層視圖。我將進(jìn)入其中的每一步看看更細(xì)節(jié)的內(nèi)容。如果你找不到自己的位置時(shí),就回頭再看看圖1,加—因?yàn)?/span>Ajax方法的異步本質(zhì),所以時(shí)序圖并不是筆直向前的。
發(fā)送一個(gè)XMLHttpRequest
我將從Ajax時(shí)序圖的起點(diǎn)開始:從瀏覽器創(chuàng)建并發(fā)送一個(gè)XMLHttpRequest。不幸的是,在不同的瀏覽器中創(chuàng)建XMLHttpRequest的方法都不一樣。列表2中示例的JavaScript函數(shù)消除了這些與瀏覽器種類相關(guān)的問題,正確檢測(cè)與當(dāng)前瀏覽器相關(guān)的方法,并返回一個(gè)可以使用的XMLHttpRequest。最好將它看成備用代碼,將它簡(jiǎn)單拷貝到你的JavaScript庫中,在需要一個(gè)XMLHttpRequest時(shí)使用它即可。
列表2:跨瀏覽器創(chuàng)建一個(gè)XMLHttpRequest
/*
* 返回一個(gè)新建的XMLHttpRequest對(duì)象,若瀏覽器不支持則失敗
*/
function newXMLHttpRequest() {
var xmlreq = false;
if (window.XMLHttpRequest) {
// 在非Microsoft瀏覽器中創(chuàng)建XMLHttpRequest對(duì)象
xmlreq = new XMLHttpRequest();
} else if (window.ActiveXObject) {
//通過MS ActiveX創(chuàng)建XMLHttpRequest
try {
// 嘗試按新版InternetExplorer方法創(chuàng)建
xmlreq = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e1) {
// 創(chuàng)建請(qǐng)求的ActiveX對(duì)象失敗
try {
// 嘗試按老版InternetExplorer方法創(chuàng)建
xmlreq = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e2) {
// 不能通過ActiveX創(chuàng)建XMLHttpRequest
}
}
}
return xmlreq;
}
稍后,我將討論如何對(duì)待不支持XMLHttpReauest的瀏覽器的一些技巧。現(xiàn)在,列表2中展示的示例函數(shù)將總是可以返回一個(gè)XMLHttpReauest實(shí)例。
回到購物車?yán)拥膱?chǎng)景中,只要用戶針對(duì)某一個(gè)目錄條目點(diǎn)擊了Add to Cart按鈕,我就要調(diào)用一個(gè)Ajax交互。名為addToCart()的onclick函數(shù)通過Ajax調(diào)用(如列表1中所示)來負(fù)責(zé)更新購物車的狀態(tài)。在列表3中,addToCart()要做的第一件事就是通過調(diào)用newXMLHttpReauest函數(shù)(如列表2中所示)來獲取一個(gè)XMLHttpRequest的實(shí)例,并且注冊(cè)一個(gè)回調(diào)函數(shù)來接受服務(wù)器響應(yīng)(我將在稍后詳細(xì)解釋,請(qǐng)參見列表6)。
因?yàn)?,此?qǐng)求將會(huì)修改服務(wù)器狀態(tài),我將使用一個(gè)HTTP POST來處理它。通過POST傳送數(shù)據(jù)需要三個(gè)步驟:首先,我需要打開一個(gè)到進(jìn)行通訊的服務(wù)器資源的POST連接—在現(xiàn)在例子中是一個(gè)URL映射為cart.do的服務(wù)器端servlet。下一步,設(shè)置XMLHttpRequest的頭信息,以標(biāo)志請(qǐng)求的內(nèi)容為form-encoded。最后,將form-encoded數(shù)據(jù)作為請(qǐng)求體,并發(fā)送此請(qǐng)求。
列表3中集中展示了這些步驟。
列表3:發(fā)送一個(gè)添加到購物車XMLHttpRequest
/*
* 通過產(chǎn)品編碼,在購物車中添加一個(gè)條目
* itemCode – 需要添加條目的產(chǎn)品編碼
*/
function addToCart(itemCode) {
// 獲取一個(gè)XMLHttpRequest實(shí)例
var req = newXMLHttpRequest();
// 設(shè)置用來從請(qǐng)求對(duì)象接收回調(diào)通知的句柄函數(shù)
var handlerFunction = getReadyStateHandler(req, updateCart);
req.onreadystatechange = handlerFunction;
// 打開一個(gè)聯(lián)接到購物車servlet的HTTP POST聯(lián)接
// 第三個(gè)參數(shù)表示請(qǐng)求是異步的
req.open("POST", "cart.do", true);
// 指示請(qǐng)求體包含form數(shù)據(jù)
req.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");
// 發(fā)送標(biāo)志需要添加到購物車中條目的form-encoded數(shù)據(jù)
req.send("action=add&item="+itemCode);
}
結(jié)合以上內(nèi)容,你可以了解到Ajax處理過程的第一部分—就是在客戶端創(chuàng)建并發(fā)送HTTP請(qǐng)求。下一步是用來處理請(qǐng)求的Java Servlet代碼。
Servlet請(qǐng)求處理
通過一個(gè)servlet來處理XMLHttpRequest與處理一個(gè)來自瀏覽器的普通的HTTP請(qǐng)求基本上相似??梢酝ㄟ^調(diào)用HttpServletRequest.getParameter()來獲取由POST請(qǐng)求體傳送過來的form-encoded數(shù)據(jù)。Ajax請(qǐng)求也與普通的WEB請(qǐng)求樣都成為此應(yīng)用同一HttpSession會(huì)話進(jìn)程的一部分。這對(duì)于購物車?yán)觼碚f很有肜,因?yàn)槲覀兛梢酝ㄟ^會(huì)話將多個(gè)請(qǐng)求的狀態(tài)都保存到同一個(gè)JavaBean購物車對(duì)象中,并可以序列化。
列表4是處理Ajax請(qǐng)求并更新購物車的簡(jiǎn)單servlet的代碼片斷。從用戶會(huì)話中檢索出一個(gè)Cart Bean,并按請(qǐng)求的參數(shù)更新它。之后Cart Bean被序列化到XML,并被寫回ServletRespone。注意,一定要將響應(yīng)內(nèi)容的類型設(shè)置為application/xml,否則,XMLHttpRequest將不能將響應(yīng)內(nèi)容解析為一個(gè)XML DOM。
列表4:處理Ajax請(qǐng)求的Servlet代碼
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws java.io.IOException {
Cart cart = getCartFromSession(req);
String action = req.getParameter("action");
String item = req.getParameter("item");
if ((action != null)&&(item != null)) {
// 在購物車中添加或移除一個(gè)條目
if ("add".equals(action)) {
cart.addItem(item);
} else if ("remove".equals(action)) {
cart.removeItems(item);
}
}
// 將購物車狀態(tài)序列化到XML
String cartXml = cart.toXml();
// 將XML寫入response.
res.setContentType("application/xml");
res.getWriter().write(cartXml);
}
列表5展示了由Cart.toXml()方法生成的XML。注意到生成的cart元素的屬性,是一個(gè)通過System.currentTimeMillis()生成的時(shí)間戳。
列表5:Cart對(duì)象序列化得到的XML
<?xml version="1.0"?>
<cart generated="1123969988414" total="$171.95">
<item code="hat001">
<name>Hat</name>
<quantity>2</quantity>
</item>
<item code="cha001">
<name>Chair</name>
<quantity>1</quantity>
</item>
<item code="dog001">
<name>Dog</name>
<quantity>1</quantity>
</item>
</cart>
如果你觀察一下下載站點(diǎn)提供的例子應(yīng)用源碼中的Cart.java,你將會(huì)看到它通過簡(jiǎn)單地追加字符串來生成XML。對(duì)于本例子來說,它已經(jīng)足夠了,我將會(huì)在本系統(tǒng)文章的以后一期中介紹一些更好的方法。
現(xiàn)在你知道了CartServlet如何響應(yīng)一個(gè)XMLHttpRequest。下一步是返回到客戶端,如何用服務(wù)器響應(yīng)來更新頁面狀態(tài)。
通過JavaScript來處理服務(wù)器響應(yīng)
XMLHttpRequest的readyState屬性是一個(gè)給出請(qǐng)求生命周期狀態(tài)的數(shù)字值。它從表示“未初始化”的0變化到表示“完成”的4。每次readyState改變時(shí),都會(huì)引發(fā)readystatechange事件,通過onreadystatechange屬性配置回調(diào)處理函數(shù)將會(huì)被調(diào)用。
在列表3中,你已看到通過調(diào)用函數(shù)getReadyStateHandler()創(chuàng)建了一個(gè)處理函數(shù),并被配置給onreadystatechange屬性。getReadyStateHandler()使用了這樣的事實(shí):函數(shù)是JavaScript中的主要對(duì)象。這意味著,函數(shù)可以作為參數(shù)被傳遞到其它函數(shù),并且可以創(chuàng)建并返回其它函數(shù)。getReadystateHandler()要做是就是返回一個(gè)函數(shù),來檢查XMLHttpRequet是否已經(jīng)完成處理,并傳遞XML服務(wù)器響應(yīng)到由調(diào)用者指定的處理函數(shù)。列表6是getReadyStateHandler()的代碼。
列表6:函數(shù)getReadyStateHandler()
/*
* Returns a function that waits for the specified XMLHttpRequest
* to complete, then passes its XML response to the given handler function.
* req - The XMLHttpRequest whose state is changing
* responseXmlHandler - Function to pass the XML response to
*/
function getReadyStateHandler(req, responseXmlHandler) {
// 返回一個(gè)監(jiān)聽XMLHttpRequest實(shí)例的匿名函數(shù)
return function () {
// 如果請(qǐng)求的狀態(tài)是“完成”
if (req.readyState == 4) {
// 檢查是否成功接收了服務(wù)器響應(yīng)
if (req.status == 200) {
// 將載有響應(yīng)信息的XML傳遞到處理函數(shù)
responseXmlHandler(req.responseXML);
} else {
// 有HTTP問題發(fā)生
alert("HTTP error: "+req.status);
}
}
}
}
HTTP狀態(tài)碼
在列表6中,XMLHttpRequest的status屬性被測(cè)試用來確定請(qǐng)求是否成功完成。當(dāng)處理簡(jiǎn)單的GET與POST請(qǐng)求,你可以認(rèn)為只要不是200(OK)的狀態(tài)就表示發(fā)生了錯(cuò)誤。若服務(wù)器發(fā)送了一個(gè)重定向響應(yīng)(例如,301或302),瀏覽器會(huì)透明地完成重定向并從新位置獲取相應(yīng)的資源;XMLHttpRequest不會(huì)看到重定向狀態(tài)碼。同時(shí),瀏覽器自動(dòng)添加一個(gè)緩存控制:對(duì)于所有XMLHttpRequest都使用no-cache header,這樣客戶端代碼就可以不用處理304(not-modified)響應(yīng)。
關(guān)于getReadyStateHandler()
getReadyStateHandler()是相對(duì)比較復(fù)雜的一段代碼,特別當(dāng)你不能熟悉閱讀JavaScript時(shí)。折中方案是在你的JavaScript庫中包含此函數(shù),你可以簡(jiǎn)單地處理Ajax服務(wù)器響應(yīng),而不用去注意XMLHttpRequest的內(nèi)部細(xì)節(jié)。重要是你自己要理解在代碼中如何使用getReadyStateHandler()。
在列表3中,你看到getReadyStateHandler()被這樣調(diào)用:
handlerFunction=getReadyStateHandler(req,updateCart)。
由它返回的函數(shù)將會(huì)檢查在req變量中的XMLHttpRequest是否已完成,并調(diào)用由updateCart指定的回調(diào)方法處理響應(yīng)XML。
提取購物車數(shù)據(jù)
列表7中展示了updateCart()中的代碼。此函數(shù)使用DOM來解析購物車XML文檔,并更新WEB頁面(參見列表1)來反映新的購物車內(nèi)容。注意對(duì)用來提取數(shù)據(jù)的XML DOM的調(diào)用。Cart元素上生成的屬性,即序列化時(shí)生成的時(shí)間戳,通過檢測(cè)它可以保證不會(huì)用老的數(shù)據(jù)來覆蓋新的購物車數(shù)據(jù)。Ajax請(qǐng)求天生就是異步的,通過這個(gè)檢測(cè)可以有效避免在過程外到達(dá)的服務(wù)器響應(yīng)的干擾。
列表7:更新頁面來反映出購物車XML文檔內(nèi)容
function updateCart(cartXML) {
// 從文檔中獲取根元素“cart”
var cart = cartXML.getElementsByTagName("cart")[0];
// 保證此文檔是最新的
var generated = cart.getAttribute("generated");
if (generated > lastCartUpdate) {
lastCartUpdate = generated;
// 清除HTML列表,用來顯示購物車內(nèi)容
var contents = document.getElementById("cart-contents");
contents.innerHTML = "";
// 在購物車內(nèi)按條目循環(huán)
var items = cart.getElementsByTagName("item");
for (var I = 0 ; I < items.length ; I++) {
var item = items[I];
// 從name與quantity元素中提取文本節(jié)點(diǎn)
var name = item.getElementsByTagName("name")[0].firstChild.nodeValue;
var quantity = item.getElementsByTagName("quantity")[0].firstChild.nodeValue;
// 為條目創(chuàng)建并添加到HTML列表中
var li = document.createElement("li");
li.appendChild(document.createTextNode(name+" x "+quantity));
contents.appendChild(li);
}
}
// 更新購物車的金額累計(jì)
document.getElementById("total").innerHTML = cart.getAttribute("total");
}
到現(xiàn)在,關(guān)于Ajax處理過程的教程已經(jīng)結(jié)束,也許你想讓應(yīng)用運(yùn)行起來,并看看它的實(shí)際運(yùn)作(參見下載部分)。這個(gè)例子非常簡(jiǎn)單,有非常大的改進(jìn)的余地。比如,我在服務(wù)器端代碼中包含了從購物車中移除條目的代碼,但從客戶端UI中沒有訪問的途徑。作為一個(gè)練習(xí),嘗試在現(xiàn)有的JavaScript基礎(chǔ)上實(shí)際這個(gè)功能。
使用Ajax的挑戰(zhàn)
與任何技術(shù)一樣,使用Ajax在相當(dāng)多的方面都可能范錯(cuò)誤。我在這兒討論的問題目前都缺少解決方案,并將會(huì)隨著Ajax的成熟而解決或提高。隨著開發(fā)Ajax應(yīng)用經(jīng)驗(yàn)的不斷獲取,開發(fā)者社區(qū)中將會(huì)出現(xiàn)最好的實(shí)踐經(jīng)驗(yàn)與指導(dǎo)方針。
XMLHttpRequest的有效性
Ajax開發(fā)者面對(duì)的一個(gè)最大問題是當(dāng)XMLHttpRequest不可用時(shí)如何反應(yīng)。雖然大部分現(xiàn)代瀏覽器支持XMLHttpRequest,但還是有少量的用戶,他們的瀏覽器不能支持,或由于瀏覽器安全設(shè)置而阻止對(duì)XMLHttpRequest的使用。若你的Web應(yīng)用發(fā)布于公司內(nèi)部的Intranet上,你很可能可以指定支持哪種瀏覽器,并可以確保XMLHttpRequest是可用的。若你在公共WEB上發(fā)布,則你必須意識(shí)到由于假定XMLHttpRequest是可用的,所有就阻止了老瀏覽器、手持設(shè)備瀏覽器等等用戶來使用你的系統(tǒng)。
然而,你應(yīng)該盡力保證應(yīng)用系統(tǒng)“正常降級(jí)”使用,在系統(tǒng)中保留適用于不支持XMLHttpRequest的瀏覽器的功能。在購物車?yán)又?,最好的方法是有一個(gè)Add to Cart按鈕,可以進(jìn)行常規(guī)的提交處理,并刷新頁面來反映購物車狀態(tài)的變化。Ajax行衛(wèi)可以在頁面被載入時(shí)通過JavaScript添加到頁面中,只在XMLHttpRequest可用的情況下,為每個(gè)Add to Cart按鈕加上JavaScript處理函數(shù)。另一個(gè)方法是在用戶登錄時(shí)檢測(cè)XMLHttpRequest,再?zèng)Q定是提供Ajax版本還是常規(guī)基于form提交的版本。
可用性考慮
圍繞著Ajax應(yīng)用的大部分問題都是很普通的問題。例如,讓用戶知道他們的輸入已經(jīng)被注冊(cè)并處理,是很重要的,因?yàn)樵?/span>XMLHttpRequest處理過程中并不能提供通常的漏斗旋轉(zhuǎn)光標(biāo)。一種方法是將“確認(rèn)”按扭上的文本替換為“正在更新中…”,以避免用戶在等待響應(yīng)時(shí)多次點(diǎn)擊按鈕。
另一個(gè)問題是,用戶可能沒有注意到他們正在觀看的頁面已經(jīng)被更新。可以通過使用各種視覺技巧來將用戶的眼光吸引到頁面的更新區(qū)域。還有一個(gè)問題是通過Ajax更新頁面打斷了瀏覽器“退回前頁”按鈕的正常工作,地址欄中的URL不能反映頁面的全部狀態(tài),并且不能使用書簽功能。參見Resource章節(jié)中列出的網(wǎng)站地址上的文章來了解更多Ajax應(yīng)用關(guān)于可用性方面的問題。
服務(wù)器負(fù)載
使用Ajax界面代替?zhèn)鹘y(tǒng)的基于form的界面可能戲劇性地增加傳遞到服務(wù)器的請(qǐng)求數(shù)量。例如,一個(gè)普通的Google搜索給服務(wù)器造成一次命中,并在用戶確認(rèn)搜索表單時(shí)發(fā)生。然而,Google Suggest,將會(huì)試圖自動(dòng)完成你的搜索詞,在用戶打字時(shí)將會(huì)往服務(wù)器發(fā)送多個(gè)請(qǐng)求。在開發(fā)一個(gè)Ajax應(yīng)用時(shí),要注意到你將會(huì)發(fā)送多少請(qǐng)求到用戶器端,以及服務(wù)器的負(fù)載指標(biāo)。你可以通過在客戶端適當(dāng)?shù)鼐彺嬲?qǐng)求、與服務(wù)器響應(yīng)來緩減負(fù)載壓力。你也應(yīng)該在設(shè)計(jì)Ajax應(yīng)用時(shí)盡量在客戶端處理更多的邏輯,而不用與服務(wù)器端通訊。
處理異步
一定要記住,沒有任何東西可以保證XMLHttpRequest將會(huì)按照它們被發(fā)送的順序來依次結(jié)束。實(shí)際上,你在設(shè)計(jì)系統(tǒng)時(shí),腦子里應(yīng)該始終假定它們不會(huì)按原來順序結(jié)束。在購物車?yán)又?,使用了一個(gè)最后更新的時(shí)間戳來保證最新的數(shù)據(jù)不會(huì)被改寫。這個(gè)非?;镜姆椒梢栽谫徫镘噲?chǎng)景中工作,但可能不能在其它情況下工作。在設(shè)計(jì)時(shí)刻就要考慮你該如何處理異步服務(wù)器響應(yīng)。
結(jié)論
你現(xiàn)在應(yīng)該對(duì)于Ajax的基本原則有了一個(gè)良好的了解,另外,你應(yīng)該理解一些更高級(jí)的隨Ajax方法而來的設(shè)計(jì)問題。創(chuàng)建一個(gè)成功的Ajax應(yīng)用需要一系列的方法—從JavaScript UI設(shè)計(jì)到服務(wù)器端架構(gòu)—但是你現(xiàn)在應(yīng)該已經(jīng)具備了需要使用到的Ajax核心知識(shí)。
There‘s good news if you‘re feeling daunted by the complexity of writing a large Ajax application using the techniques demonstrated here. Just as frameworks like Struts, Spring, and Hibernate have evolved to abstract Web application development away from the low-level details of the Servlet API and JDBC, so toolkits are appearing to ease Ajax development. Some of these focus solely on the client side, providing easy ways to add visual effects to your pages or streamlining the use of XMLHttpRequest. Others go further, providing means to automatically generate Ajax interfaces from server-side code. These frameworks do the heavy lifting for you, so that you can take a more high-level approach to Ajax development. I‘ll be looking at some of them in this series.
The Ajax community is fast moving, and there‘s a great deal of valuable information out there. Before reading the next installment in this series, I recommend that you consult the articles listed in the Resources section, especially if you‘re new to Ajax or client-side development. You should also take some time to study the example source code and think about ways to improve it.
In the next article in this series, I‘ll discuss the XMLHttpRequest API in more detail and suggest ways to create XML easily from your JavaBeans. I‘ll also show you alternatives to XML for Ajax data transfer, such as the JSON (JavaScript Object Notation) lightweight data-interchange format.
Download
Sample code j-ajax1.zip 8 KB FTP
Resources
Learn
"Beyond the DOM" (Dethe Elza, developerWorks, May 2005): Useful JavaScript techniques for XML document access.
"Ajax and scripting Web services with E4X" (Paul Fremantle and Anthony Elder, developerWorks, April 2005): Use Ajax to make SOAP calls in browsers that support the E4X JavaScript extension.
"Ajax: A New Approach to Web Applications" (Jesse James Garrett, Adaptive Path, February 2005): The seminal essay that gave Ajax its name.
The Java BluePrints Solutions Catalog: Documents the application of Ajax to several common Web application scenarios.
AjaxPatterns.org: A wiki that includes several UI techniques to improve Ajax applications.
XMLHttpRequest Usability Guidelines: Suggestions for using Ajax to enhance user experience.
Ajax Mistakes: Usability problems that Ajax applications should avoid.
The Java technology zone: Find articles about every aspect of Java programming.
Get products and technologies
Mozilla Firefox: The DOM Inspector and JavaScript Debugger extension take a lot of the pain out of Ajax development.
Discuss
Participate in the discussion forum for this content.
developerWorks blogs: Get involved in the developerWorks community.
About the author
Philip McCarthy is software development consultant specializing in Java and Web technologies. He is currently working on Hewlett Packard‘s Digital Media Platform project at HP Labs, Bristol. In recent years Phil has developed several rich Web clients employing asynchronous server communication and DOM scripting. He is glad we now have a name for them. You can get in touch with Phil at philmccarthy@gmail.com.
聯(lián)系客服