JavaScript異步調(diào)用框架的代碼實(shí)現(xiàn)
在上一篇文章里,我們說到了要實(shí)現(xiàn)一個(gè)用于JavaScript異步調(diào)用的Async.Operation類,通過addCallback方法傳遞回調(diào)函數(shù),并且通過yield方法返回回調(diào)結(jié)果?,F(xiàn)在我們就來實(shí)現(xiàn)這個(gè)類吧。
類結(jié)構(gòu)
首先我們來搭一個(gè)架子,把需要用到的似有變量都列出來。我們需要一個(gè)數(shù)組,來保存回調(diào)函數(shù)列表;需要一個(gè)標(biāo)志位,來表示異步操作是否已完成;還可以學(xué)IAsyncResult,加一個(gè)state,允許異步操作的實(shí)現(xiàn)者對(duì)外暴露自定義的執(zhí)行狀態(tài);最后加一個(gè)變量保存異步操作結(jié)果。
- Async = {
- Operation: {
- var callbackQueue = [];
- this.result = undefined;
- this.state = "waiting";
- this.completed = false;
- }
- }
addCallback方法
接下來,我們要實(shí)現(xiàn)addCallback方法,它的工作職責(zé)很簡(jiǎn)單,就是把回調(diào)函數(shù)放到callbackQueue中。此外,如果此時(shí)completed為true,說明異步操作已經(jīng)yield過了,則立即調(diào)用此回調(diào)。
- this.yield = function(callback) {
- callbackQueue.push(callback);
- if (this.completed) {
- this.yield(this.result);
- }
- return this;
- }
我們假設(shè)yield方法會(huì)把callbackQueue中的回調(diào)函數(shù)逐個(gè)取出來然后調(diào)用,因此如果compeleted為true,則使用已有的result再調(diào)用一次yield就可以了,這樣yield自然會(huì)調(diào)用這次添加到callbackQueue的回調(diào)函數(shù)。
至于最后的return this;,只是為了方便jQuery風(fēng)格的鏈?zhǔn)綄懛?,可以通過點(diǎn)號(hào)分隔連續(xù)添加多個(gè)回調(diào)函數(shù)來實(shí)現(xiàn)JavaScript異步調(diào)用:
- asyncOperation(argument)
- .addCallback(firstCallback)
- .addCallback(secondCallback);
yield方法
最后,我們要實(shí)現(xiàn)yield方法。它需要將callbackQueue中的回調(diào)函數(shù)逐個(gè)取出來,然后都調(diào)用一遍,并且保證這個(gè)操作是異步吧。
- 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的實(shí)際操作是異步進(jìn)行的。然后我們把用戶傳入yield的結(jié)果及相關(guān)狀態(tài)更新到對(duì)象屬性之上,最后遍歷callbackQueue調(diào)用所有的回調(diào)函數(shù)。
小結(jié)
這樣我們就做好了一個(gè)簡(jiǎn)單的JavaScript異步調(diào)用框架,完整的代碼如下:
- Async = {
- Operation: function() {
- var callbackQueue = [];
- this.result = undefined;
- this.state = "running";
- this.completed = false;
- 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;
- };
- this.addCallback = function(callback) {
- callbackQueue.push(callback);
- if (this.completed) {
- this.yield(this.result);
- }
- return this;
- };
- }
- };
這個(gè)框架能夠很好的解決調(diào)用棧中出現(xiàn)同步異步操作并存的情況,假設(shè)所有函數(shù)都返回Async.Operation,框架的使用者可以使用一種統(tǒng)一的模式來編寫代碼,處理函數(shù)返回,而無需關(guān)心這個(gè)函數(shù)實(shí)際上是同步返回了還是異步返回了。
對(duì)于串行調(diào)用多個(gè)異步函數(shù)的情況,我們現(xiàn)在可以用嵌套addCallback的方式來書寫,但隨著嵌套層數(shù)的增多,代碼會(huì)變得越來越不美觀:
- firstAsyncOperation().addCallback(function() {
- secondAsyncOperation().addCallback(function() {
- thirdAsyncOperation().addCallback(function() {
- finalSyncOperation();
- });
- });
- });
我們能否把嵌套形式改為jQuery風(fēng)格的鏈?zhǔn)綄懛??這是我們接下來要思考的問題。
【編輯推薦】