類結構
首先我們來搭一個架子,把需要用到的似有變數都列出來。我們需要一個數組,來儲存回呼函數列表;需要一個標誌位,來表示非同步作業是否已完成;還可以學IAsyncResult,加一個state,允許非同步作業的實現者對外暴露自訂的執行狀態;最後加一個變數儲存非同步作業結果。
複製代碼 代碼如下:Async = {
Operation: {
var callbackQueue = [];
this.result = undefined;
this.state = "waiting";
this.completed = false;
}
}
addCallback方法
接下來,我們要實現addCallback方法,它的工作職責很簡單,就是把回呼函數放到callbackQueue中。此外,如果此時completed為true,說明非同步作業已經yield過了,則立即調用此回調。 複製代碼 代碼如下:this.yield = function(callback) {
callbackQueue.push(callback);
if (this.completed) {
this.yield(this.result);
}
return this;
}
我們假設yield方法會把callbackQueue中的回呼函數逐個取出來然後調用,因此如果compeleted為true,則使用已有的result再調用一次yield就可以了,這樣yield自然會調用這次添加到callbackQueue的回呼函數。
至於最後的return this;,只是為了方便jQuery風格的鏈式寫法,可以通過點號分隔連續添加多個回呼函數: 複製代碼 代碼如下:asyncOperation(argument)
.addCallback(firstCallback)
.addCallback(secondCallback);
yield方法
最後,我們要實現yield方法。它需要將callbackQueue中的回呼函數逐個取出來,然後都調用一遍,並且保證這個操作是非同步吧。 複製代碼 代碼如下:this.yield = function(result) {
var self = this;
setTimeout(function() {
self.result = result;
self.state = "completed";
self.completed = true;
while (callbackQueue.length > 0) {
var callback = callbackQueue.shift();
callback(self.result);
}
}, 1);
return this;
}
通過使用setTimeout,我們確保了yield的實際操作是非同步進行的。然後我們把使用者傳入yield的結果及相關狀態更新到對象屬性之上,最後遍曆callbackQueue調用所有的回呼函數。
小結
這樣我們就做好了一個簡單的JavaScript非同步呼叫架構,完整的代碼可以看這裡:非同步呼叫架構Async.Operation。
這個架構能夠很好的解決調用棧中出現同步非同步作業並存的情況,假設所有函數都返回Async.Operation,架構的使用者可以使用一種統一的模式來編寫代碼,處理函數返回,而無需關心這個函數實際上是同步返回了還是非同步返回了。
對於串列調用多個非同步函數的情況,我們現在可以用嵌套addCallback的方式來書寫,但隨著嵌套層數的增多,代碼會變得越來越不美觀: 複製代碼 代碼如下:firstAsyncOperation().addCallback(function() {
secondAsyncOperation().addCallback(function() {
thirdAsyncOperation().addCallback(function() {
finalSyncOperation();
});
});
});
我們能否把嵌套形式改為jQuery風格的鏈式寫法呢?這是我們接下來要思考的問題,如果你不希望錯過相關討論的話