引言在閱讀本文之前,,您需要具備以下知識(shí):
Dojo 的應(yīng)用將貫穿本文,,選擇 Dojo 的主要原因有以下兩點(diǎn):
基于上述內(nèi)容,本文的主要內(nèi)容可以歸納如下:
準(zhǔn)備工作服務(wù)器端業(yè)務(wù)描述由于本文主要討論客戶端實(shí)現(xiàn) Ajax 請(qǐng)求,。在此不介紹服務(wù)器端的實(shí)現(xiàn)方式,并且認(rèn)為服務(wù)器已經(jīng)實(shí)現(xiàn)了所有我們需要的功能,,僅以最簡單的方式描述服務(wù)器端的業(yè)務(wù),。 讓我們用一個(gè)示例來說明,圖 1 展示了服務(wù)器與客戶端的交互,。 圖 1. 客戶端與服務(wù)器端數(shù)據(jù)交互示現(xiàn)在在服務(wù)器端有一個(gè)音樂管理系統(tǒng),,里面的音樂按照風(fēng)格進(jìn)行分類。服務(wù)器提供兩類 REST 服務(wù):
客戶端與服務(wù)器端的數(shù)據(jù)以 JSON 格式進(jìn)行交互,。 準(zhǔn)備開發(fā)環(huán)境和調(diào)試工具下載并安裝 Firefox 瀏覽器,,并安裝 Firebug 插件。 使用 Dojo 進(jìn)行基本的 Ajax 請(qǐng)求處理dojo.xhr 的使用方法HTTP 協(xié)議中的四種請(qǐng)求是分別是:Get(讀?。?,Post(更新),Put(創(chuàng)建),,Delete(刪除),。 Dojo 以 XmlHttpRequest 對(duì)象為基礎(chǔ),提供了一組靜態(tài)函數(shù)來支持這些 HTTP 請(qǐng)求,。這些方法定義在 dojo/_base/xhr.js 中,,因此在使用的時(shí)候不需要顯式的引用。 清單 1 顯示了一個(gè)示例,,這個(gè)示例獲取所有輕音樂歌曲,,并將獲得的數(shù)據(jù)打印在 Firebug 的 console 面板上,。 清單 1. dojo.xhrGet 的使用dojo.xhrGet({ url: "/music/softMusic", sync: false, handleAs: "json", handle: function(response, ioArgs) { console.log(response); } }); sync 表示當(dāng)前的 xhr 函數(shù)在數(shù)據(jù)返回前是否阻塞,這個(gè)值默認(rèn)是 false,,即不阻塞,。有關(guān) Dojo 中 xhr 函數(shù)的詳細(xì)使用請(qǐng)參考 掌握 Dojo 工具包,第 2 部分: XHR 框架與 Dojo 以獲得更多的信息,。 服務(wù)器以 JSON 格式返回歌曲信息如清單 2 所示: 清單 2. 服務(wù)器端返回 /music/{categoryOfMusic} 數(shù)據(jù)示例{ "songs": [ { name: "softMusic1", singer: "A", category: "soft" }, { name: "softMusic2", singer: "B", category: "soft" }, { name: "softMusic3", singer: "C", category: "soft" } ] } dojo.Deferred 對(duì)象和為 dojo.xhr 函數(shù)添加回調(diào)函數(shù)Dojo 提供的所有 xhr 函數(shù)都會(huì)返回一個(gè)"dojo.Deferred"對(duì)象,。更多有關(guān)"dojo.Deferred"的信息,請(qǐng)參考 dojo.Deferred 參考文檔,。Deferred 對(duì)象是 Dojo 提供的用于異步編程模式的強(qiáng)大工具,。"dojo.Deferred"有三個(gè)狀態(tài),初始化時(shí)是"unresolve"狀態(tài),;當(dāng)它所等待的事件發(fā)生時(shí) , 進(jìn)入"resolve" 狀態(tài),;當(dāng)發(fā)生錯(cuò)誤了,進(jìn)入"reject"狀態(tài),。當(dāng) Deferred 對(duì)象由"unresolve"狀態(tài)進(jìn)入"resolve" 狀態(tài)或"reject"狀態(tài)時(shí),,會(huì)調(diào)用事先注冊(cè)的回調(diào)函數(shù)。對(duì)于 dojo.xhr 返回的 Deferred 對(duì)象,,所注冊(cè)的回調(diào)函數(shù)會(huì)在 Ajax 請(qǐng)求返回時(shí)或者出錯(cuò)時(shí)調(diào)用,。通過注冊(cè)回調(diào)函數(shù),可以替代的 dojo.xhr 中的 handle 方法,。例如上面的一段代碼可以寫成如下所示: 清單 3. 為 dojo.xhrGet 添加回調(diào)函數(shù)var deferred = dojo.xhrGet({ url: "/music/softMusic", handleAs: "json" }); deferred.addBoth(function(response) { console.log(response); }); addBoth 是為正常返回和出錯(cuò)返回添加相同的回調(diào)函數(shù),。與 dojo.xhr 函數(shù)的參數(shù) handle 起相同作用。 基于回調(diào)函數(shù)的小規(guī)模批量 Ajax 請(qǐng)求處理 因?yàn)?Ajax 請(qǐng)求是一種異步操作,,客戶端不知道什么時(shí)候能獲得返回的數(shù)據(jù),,所以進(jìn)行批量 Ajax 請(qǐng)求時(shí),客戶端不能很好的同時(shí)管理多個(gè) Ajax 請(qǐng)求返回的數(shù)據(jù),。例如,,當(dāng)需要多個(gè) Ajax 請(qǐng)求都返回之后將得到的數(shù)據(jù)一起輸出,不論是分別監(jiān)測這些 Ajax 請(qǐng)求還是延時(shí)一個(gè)足夠長的時(shí)間以確保所有的 Ajax 請(qǐng)求都返回,,都不是明智的方法,。 dojo.xhr 函數(shù)可以為 Ajax 請(qǐng)求添加任意的回調(diào)函數(shù)。這樣在前一次請(qǐng)求的回調(diào)函數(shù)中再發(fā)送 Ajax 請(qǐng)求,。當(dāng)最后一個(gè) Ajax 請(qǐng)求返回時(shí),,必然所有的 Ajax 請(qǐng)求都已經(jīng)返回。通過這種方法,,可以實(shí)現(xiàn)小規(guī)模的批量 Ajax 請(qǐng)求管理,。 例如,,回到我們的音樂管理系統(tǒng)?,F(xiàn)在需要獲取第 3 首輕音樂的詳細(xì)信息,,并輸出在 Firebug 的 console 面板上。由于我們事先不知道第 3 首輕音樂的名字,,無法直接獲取它的詳細(xì)信息,。只能先獲得所有的輕音樂,在返回的 JSON 格式數(shù)據(jù)中找到第三首音樂的概要信息,,再發(fā)送一次 Ajax 請(qǐng)求獲得該音樂的詳細(xì)信息,。清單 4 展示了一種實(shí)現(xiàn)方式。 清單 4. 在回調(diào)函數(shù)中發(fā)送另一次 Ajax 請(qǐng)求var deferred = dojo.xhrGet({ url: "/music/softMusic", handleAs: "json" }); deferred.then(function(response) { var songs = response.songs; return dojo.xhrGet({ url: "/music/" + songs[2].name, handleAs: "json" }); }, function(errResponse) { console.log(errResponse); }).addBoth(function(response) { console.log(response); }); Deferred 對(duì)象的 then 方法接收兩個(gè)參數(shù),,這兩個(gè)參數(shù)都是函數(shù),,第一個(gè)函數(shù)在 Deferred 達(dá)到"resovled"時(shí)調(diào)用,第二個(gè)函數(shù)在 Deferred 達(dá)到"rejected"時(shí)調(diào)用,。 服務(wù)器以 JSON 格式返回歌曲的詳細(xì)信息如清單 5 所示: 清單 5. 服務(wù)器端返回 /music/{nameOfSong} 數(shù)據(jù)示例{ name: "softMusic3", singer: "C", year: "2012-03-21", … category: "soft" } 這種方法只能串行的處理多個(gè) Ajax 請(qǐng)求,,并且,隨著 Ajax 請(qǐng)求數(shù)增多,,所需要的代碼也需要相應(yīng)的增加,,因此只適合進(jìn)行小規(guī)模批量 Ajax 請(qǐng)求處理。 使用 Dojo 并發(fā)的處理多個(gè) Ajax 請(qǐng)求實(shí)現(xiàn)原理由于 HTTP 協(xié)議是無狀態(tài)的(Stateless),,HTTP 的無狀態(tài)特性簡化了服務(wù)器的設(shè)計(jì),,使服務(wù)器更容易支持大量并發(fā)的 HTTP 請(qǐng)求。在客戶端,,采用 Dojo 作為開發(fā)工具,,由于 dojo.xhr 函數(shù)返回的是一個(gè)"dojo.Deferred"對(duì)象。因此,,可以通過管理多個(gè) dojo.xhr 函數(shù)返回的 Deferred 對(duì)象來管理多個(gè)并發(fā)的 Ajax 請(qǐng)求,。 用 dojo.DeferredList 和 dojox.lang.async.par 實(shí)現(xiàn)比較Dojo 中有多種方法管理異步編程對(duì)象"dojo.Deferred"。 首先,,可以用 dojo.DeferredList 管理多個(gè) Deferred 對(duì)象,。dojo.DeferredList 本身是一個(gè) dojo.Deferred 的子類。因此,,它也有相應(yīng)的三種狀態(tài),,也有對(duì)應(yīng)的回調(diào)函數(shù)。DeferredList 達(dá)到"resolved"的條件是所有它所管理的 Deferred 對(duì)象都達(dá)到"resolved"或"rejected"狀態(tài),。在下面的例子中,,DeferredList 達(dá)到"resolved"的條件是所有的 Ajax 請(qǐng)求都返回(不論是成功返回還是出錯(cuò)返回),而 DeferredList 的回調(diào)函數(shù)獲得的參數(shù)是一個(gè)二元數(shù)值對(duì)的數(shù)組,,二元數(shù)值對(duì)對(duì)應(yīng)了各個(gè) Ajax 請(qǐng)求的返回信息,。其中第一個(gè)數(shù)值是一個(gè) boolean 值,表示 Ajax 請(qǐng)求是否成功返回,;第二個(gè)數(shù)值是 Ajax 請(qǐng)求返回的信息,。不論各個(gè) Ajax 請(qǐng)求的返回順序如何,,該數(shù)組的順序?qū)?yīng)于傳入 DeferredList 的 Deferred 對(duì)象的順序。 同時(shí),,我們也可以用 dojox.lang.async 模塊中的一個(gè)靜態(tài)函數(shù) dojox.lang.async.par 管理并發(fā)的 Ajax 請(qǐng)求管理,。這個(gè)靜態(tài)函數(shù)接受一個(gè)函數(shù)的數(shù)組作為參數(shù),并返回一個(gè)"dojo.Deferred"對(duì)象,。在管理并發(fā)的 Ajax 請(qǐng)求時(shí),,可以使得傳入的函數(shù)返回時(shí)調(diào)用 dojo.xhr 函數(shù)。該函數(shù)返回的 Deferred 對(duì)象達(dá)到"resolved"狀態(tài)的條件是上述函數(shù)數(shù)組中的函數(shù)成功返回或者函數(shù)返回的 Deferred 對(duì)象都達(dá)到"resolved"狀態(tài),。否則,,該 Deferred 對(duì)象進(jìn)入"rejected"狀態(tài)。該 Deferred 對(duì)象對(duì)應(yīng)"resolved"狀態(tài)的回調(diào)函數(shù)能夠獲得一個(gè)數(shù)組作為參數(shù),,這個(gè)數(shù)組包含了各個(gè) Ajax 請(qǐng)求的成功返回信息,。不論各個(gè) Ajax 請(qǐng)求的返回順序如何,該數(shù)組的順序?qū)?yīng)于傳入 dojox.lang.async.par 的函數(shù)的順序,。 并發(fā)處理多個(gè) Ajax 請(qǐng)求的示例現(xiàn)在,,對(duì)于我們的音樂管理系統(tǒng),我們要同時(shí)獲得所有的輕音樂,,民謠,,鄉(xiāng)村音樂 , 并在 Firebug 的 console 面板顯示。清單 6 展示了用上述的兩種方法實(shí)現(xiàn)的示例,。 清單 6. 并發(fā)處理 Ajax 請(qǐng)求示例dojo.require("dojo.DeferredList"); dojo.require("dojox.lang.async"); function getSoftMusic() { return dojo.xhrGet({ url: "/music/softMusic", handleAs: "json" }); } function getFolkMusic() { return dojo.xhrGet({ url: "/music/folkMusic", handleAs: "json" }); } function getCountryMusic() { return dojo.xhrGet({ url: "/music/countryMusic", handleAs: "json" }); } // 利用 dojo.DeferredList 處理并發(fā)的 Ajax 請(qǐng)求 var d1 = getSoftMusic(), d2 = getFolkMusic(), d3 = getCountryMusic(), defList = new dojo.DeferredList([d1, d2, d3]); defList.then(function(results) { dojo.forEach(results, function(result) { console.log(result[1]); }); }); // 利用 dojox.lang.async.par 處理并發(fā)的 Ajax 請(qǐng)求 var arrayOfAjax = [getSoftMusic, getFolkMusic, getCountryMusic]; dojox.lang.async.par(arrayOfAjax)().then(function(results) { dojo.forEach(results, function(result) { console.log(result); }); }); 兩種解決方案的對(duì)比從上面的示例可以看出,,上述的兩種方法都是用一個(gè) Deferred 對(duì)象管理多個(gè) Deferred 對(duì)象(DeferredList 是 Deferred 的子類,因此 DeferredList 的實(shí)例也可以認(rèn)為是一個(gè) Deferred 對(duì)象),。通過為作為管理者的 Deferred 對(duì)象增加回調(diào)函數(shù)來通知客戶端程序多個(gè) Ajax 請(qǐng)求已經(jīng)返回,。 相比之下,用 DeferredList 更為靈活,。DeferredList 在默認(rèn)情況下,,會(huì)完成所有的 Ajax 請(qǐng)求,即使某一個(gè) Ajax 請(qǐng)求失敗了,,最后 DeferredList 仍能夠觸發(fā)"resolved"狀態(tài)的回調(diào)函數(shù),,并將相應(yīng)的信息置于回調(diào)函數(shù)的參數(shù)中。而 dojox.lang.async.par 只會(huì)在所有的 Ajax 請(qǐng)求成功返回之后才會(huì)將各個(gè) Ajax 請(qǐng)求的返回的信息傳遞給回調(diào)函數(shù),。當(dāng)某一個(gè) Ajax 請(qǐng)求失敗了,,dojox.lang.async.par 會(huì)將排在這個(gè)請(qǐng)求之后的所有 Ajax 請(qǐng)求取消。并觸發(fā)"rejected"狀態(tài)的回調(diào)函數(shù),。 使用 Dojo 串行的處理多個(gè) Ajax 請(qǐng)求實(shí)現(xiàn)原理利用前文中所述的方法可以串行的處理多個(gè) Ajax 請(qǐng)求,。但是存在一個(gè)問題,當(dāng)需要串行處理的 Ajax 請(qǐng)求較多時(shí),代碼將顯得又亂又長,。并且,,很多時(shí)候程序事先并不知道要串行處理多少個(gè) Ajax 請(qǐng)求,因?yàn)檫@是由用戶的操作決定的,。在 dojox.lang.async 模塊中,有一個(gè)靜態(tài)函數(shù) dojox.lang.async.seq 能夠很好的幫我們解決這些問題,。 用 dojox.lang.async.seq 的實(shí)現(xiàn)和示例dojox.lang.async.seq 也是接受一個(gè)函數(shù)的數(shù)組作為參數(shù),,并返回一個(gè)"dojo.Deferred"對(duì)象。在管理串行的 Ajax 請(qǐng)求時(shí),,可以使得傳入的函數(shù)返回時(shí)調(diào)用 dojo.xhr 函數(shù),。該函數(shù)返回的 Deferred 對(duì)象達(dá)到"resolved"狀態(tài)的條件是上述函數(shù)數(shù)組中的函數(shù)成功返回或者函數(shù)返回的 Deferred 對(duì)象都達(dá)到"resolved"狀態(tài)。否則,,該 Deferred 對(duì)象進(jìn)入"rejected"狀態(tài),。 回到之前的例子,現(xiàn)在我們需要?jiǎng)h除輕音樂,,民謠,,鄉(xiāng)村音樂。但是很不幸,,服務(wù)器規(guī)定刪除操作不能并發(fā)進(jìn)行,,我們只能在刪除一個(gè)分類之后再刪除另一個(gè)分類。 清單 7 展示了實(shí)現(xiàn)的示例,。 清單 7. 串行處理 Ajax 請(qǐng)求示例dojo.require("dojox.lang.async"); function deleteSoftMusic() { return dojo.xhrDelete({ url: "/music/softMusic", handle: function(response) { console.log(response); } }); } function deleteFolkMusic() { return dojo.xhrDelete({ url: "/music/folkMusic", handle: function(response) { console.log(response); } }); } function deleteCountryMusic() { return dojo.xhrDelete({ url: "/music/countryMusic", handle: function(response) { console.log(response); } }); } var arrayOfAjax = [deleteSoftMusic, deleteFolkMusic, getCountryMusic]; dojox.lang.async.seq(arrayOfAjax)().allBoth(function(result) { console.log(result); }); 當(dāng) dojox.lang.async.seq 管理的某一個(gè) Ajax 請(qǐng)求失敗了,,排在其之后的 Ajax 請(qǐng)求將不再執(zhí)行。并且 dojox.lang.async.seq 返回的 Deferred 對(duì)象會(huì)進(jìn)入"rejected"狀態(tài),。 總結(jié)通過以上的介紹和舉例,,我們了解了如何以 Dojo 作為工具,管理批量 Ajax 請(qǐng)求,。Ajax 請(qǐng)求是一種異步操作,,客戶端無法知道這種異步操作什么時(shí)候返回,是否能成功返回,。因此,,批量處理 Ajax 請(qǐng)求的難點(diǎn)在于同時(shí)管理。本文講述了一種結(jié)合 dojo.xhr 函數(shù)和 dojo.Deferred 對(duì)象的管理方式,。用這種方式能夠以多種方式管理批量 Ajax 請(qǐng)求,,希望能為您的實(shí)際應(yīng)用帶來一定的啟發(fā)。 |
|