JavaScript 非同步呼叫架構 (Part 6 – 執行個體 模式)

來源:互聯網
上載者:User

封裝Ajax
設計Async.Operation的最初目的就是解決Ajax調用需要傳遞callback參數的問題,為此我們先把Ajax請求封裝為Async.Operation。我在這裡使用的是jQuery,當然無論你用什麼基礎庫,在使用Async.Operation時都可以做這種簡單的封裝。 複製代碼 代碼如下:var Ajax = {};

Ajax.get = function(url, data) {
var operation = new Async.Operation();
$.get(url, data, function(result) { operation.yield(result); }, "json");
return operation;
};

Ajax.post = function(url, data) {
var operation = new Async.Operation();
$.post(url, data, function(result) { operation.yield(result); }, "json");
return operation;
};

在我所調用的伺服器端API中,只需要GET和POST,且資料都為JSON,所以我就直接把jQuery提供的其它Ajax選項屏蔽掉了,並設定資料類型為JSON。在你的項目當中,也可以用類似的方式將Ajax封裝為若干僅僅返回Async.Operation的方法,將jQuery提供的選項都封裝在Ajax這一層內,不再向上層暴露這些選項。

調用Ajax
把Ajax封裝好後,我們就可以開始專心寫商務邏輯了。

假設我們有一個Friend對象,它的get方法用於返回單個好友對象,而getAll方法用於返回所有好友對象。於此對應的是兩個伺服器端API,friend介面會返回單個好友JSON,而friendlist介面會返回所有好友名稱組成的JSON。

首先我們看看較為基礎的get方法怎麼寫: 複製代碼 代碼如下:function get(name) {
return Ajax.get("/friend", "name=" + encodeURIComponent(name));
}

就這麼簡單?對的,假如伺服器端API返回的JSON結構正好就是你要的好友對象結構的話。如果JSON結構和好友對象結構是異構的,或許你還要加點代碼來把JSON映射為對象: 複製代碼 代碼如下:function get(name) {
var operation = new Async.Operation()
Ajax.get("/friend", "name=" + encodeURIComponent(name))
.addCallback(function(json) {
operation.yield(createFriendFromJson(json));
});
return operation;
}

Ajax隊列
接下來我們要編寫的是getAll方法。因為friendlist介面只返回好友名稱列表,因此在取得這份列表後我們還要逐一調用get方法擷取具體的好友對象。考慮到在同時進行多個friend介面調用可能觸發伺服器的防攻擊策略,導致被關小黑屋一段時間,所以對friend介面的調用必須排隊。 複製代碼 代碼如下:function getAll(){
var operation = new Async.Operation();
var friends = [];
var chain = Async.chain();
Ajax.get("/friendlist", "")
.addCallback(function(json) {
for (var i = 0; i < json.length; i++) {
chain.next(function() {
return get(json.shift())
.addCallback(function(friend) { friends.push(friend); });
});
}
chain
.next(function() { operation.yield(friends); })
.go();
})
return operation;
}

在這裡,我們假設friendlist介面返回的JSON就是一個Array,在擷取到這個Array後構造一個等長的非同步呼叫隊列,其中每一個調用的邏輯都是一樣的——取出Array中首個好友的名稱,用get方法擷取對應的好友對象,再將好友對象放入另一個Array中。在調用隊列的末端,我們再追加了一個調用,用於返回儲存好友對象的Array。

在這個例子當中,我們沒有利用調用隊列會把上一個函數的結果傳遞給下一個函數的特性,不過也足夠展示調用隊列的用途了——讓多個底層為Ajax請求的非同步作業按照固定的順序阻塞式執行。

由於底層非同步函數返回的就是Async.Operation,你可以直接把它傳遞給next方法,也可以用匿名函數封裝後傳遞給next方法,而匿名函數內部只需要一個return。

延時函數
在上面的例子中,使用隊列是為了避免觸發伺服器的防攻擊策略,但有時候這還是不夠的。例如說,伺服器要求兩個請求之間至少間隔500毫秒,否則就認為是攻擊,那麼我們就要在隊列裡面插入這個間隔了。

在原本next方法調用的匿名函數中手動加入setTimeout是一個辦法,但為什麼我們不寫一個輔助函數來解決這類問題呢?讓我們來寫一個輔助方法並讓它和Async.Operation無縫結合起來。 複製代碼 代碼如下:Async.wait = function(delay, context) {
var operation = new Async.Operation();
setTimeout(function() { operation.yield(context); }, delay);
return operation;
};

Async.Operation.prototype.wait = function(delay, context) {
this.next(function(context) { return Async.wait(delay, context); });
}

在有了這個輔助方法後,我們就可以在上述getAll方法中輕鬆實現在每個Ajax請求之間間隔500毫秒。在for迴圈內的加上對wait的調用就可以了。 複製代碼 代碼如下:for (var i = 0; i < json.length; i++) {
chain
.wait(500)
.next(function() {
return get(json.shift())
.addCallback(function(friend) { friends.push(friend); });
});
}

小結
通過一些簡單的例子,我們瞭解到了Async.Operation常見的使用方式,以及在有需要的時候如何擴充它的功能。希望Async.Operation能夠有效協助大家提高Ajax應用的代碼可讀性。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.