非同步程式設計之Promise 3 拓展高階

2022-03-10 05:23:27 字數 4386 閱讀 4269

非同步程式設計系列教程:

(翻譯)非同步程式設計之promise(1)——初見魅力

非同步程式設計之promise(2):**原理

非同步程式設計之promise(3):拓展高階

非同步程式設計之generator(1)——領略魅力

非同步程式設計之generator(2)——剖析特性

非同步程式設計之co——原始碼分析

在前面的文章中,通過了解promise能做什麼,實踐動手從原理上了解promise/deferred模式的用法,相信大家應該更期待這次的功能拓展。我們不僅需要讓單非同步操作promise化,我們還需要從實際出發,拓展更多有用的功能。直接看一下我們這一次需要做的兩個功能:

多非同步並行控制

多非同步序列佇列

這兩個功能用我們之前自己寫的簡陋promise庫,是無法做到的。我們不能在指定多個promise非同步完成後,再觸發**。也不能讓多個promise非同步像排隊一樣,乙個乙個的進行,甚至下乙個promise的引數是依賴上乙個promise的。這就是我們接下來需要解決的問題:

在凍手之前,我們先想一想大致的思路吧。首先我們肯定是併發了多個非同步,我們需要做的僅僅就是,監控所有併發的非同步,並讓最後乙個非同步觸發resolve**函式。當然錯誤處理的話,就是當有乙個非同步錯誤,直接就reject掉宣布非同步失敗結束。一般監視併發,我們都會有乙個哨兵變數,每完成乙個非同步,就對哨兵進行維護並檢測非同步是否結束。

那我們的api應該怎麼設定呢?樸靈老師的書上是這樣的:deferred.all([promise1, promise2]).then()。從這裡我們可以看出,就是由各個小promise組成了乙個大的promise,並在大promise中進行接下來的操作。一起看一下**吧:

deferred.prototype.all = function(promises)

}, function(err));

});return this.promise;

};

// 這段**是輸出兩個檔案裡,字串length最大的值。

var r1 = readfile("hello.txt", 'utf-8');

var r2 = readfile("hello2.txt", 'utf-8');

var deferred = new deferred(); // 初始化乙個延時物件。

deferred.all([r1, r2]).then(function(res));

});that's easy, right?! 我們這裡僅僅是實現原理,是不成熟的,若實際使用中,更推薦q.js。現在我們將需要並行的promise放到乙個陣列裡,不出錯就會得到每一次並行的結果,並儲存在result中,最後返回得到並進行相應處理。當然我們也可以很清楚感受到它的侷限,並行的promise是相互獨立無依賴的。當多個非同步開始有依賴了,我們該怎麼做呢?這就是我們接下來要討論的。

一般來說,多非同步序列執行,通過最簡單的巢狀**即可解決。但我們可以想象,我們最終的理想形態應該是鏈式結構的。res依賴以上的步驟,我們通過鏈式結構可以更清晰易懂,有助於我們進行流程控制。

--------巢狀**---------

api1(function(v1))

})})

});--------鏈式呼叫---------

promise()

.then(api1)

.then(api2)

.then(api3)

.then(function(res))

還是從想開始,我們需要做到promise支援鏈式執行,第一感覺的資料結構就是佇列,就是那個fifo先進先出的佇列。我們將所有的**都壓入佇列中,完成乙個就取乙個出來執行。但是更關鍵的問題在於,前面乙個promise的值,如何傳到下乙個promise中。樸靈大大在這裡給出的解決方案是:promise執行**時,一旦檢測到返回的是新的promise物件,會將當前deferred延遲物件中的promise引用換成新的promise物件。而那個**佇列,也同樣轉移到了新promise上。

不知道大家有沒有聽懂大概個意思,如果還是不太清楚,我們可以思考一下,再對比一下實現的**,就應該能看懂了。這次我們需要對以往的**,做乙個較大的改變,我們不再使用events.eventemitter來進行事件觸發了。為了能鏈式的呼叫**,我們會將事件觸發放在陣列佇列裡,並按順序進行觸發。因為**進行了較大的改變,我們逐個逐個看**。

var promise = function();

promise.prototype.then = function(resolve, reject);

if(typeof resolve === 'function')

if(typeof reject === 'function')

this.queue.push(handler); // 將**事件推入到陣列佇列中

return this;

};

這一段**,我們最重要的是定義了乙個queue屬性。它是用來存放在then(resolve, reject)中的resolvereject方法的。最後我們會將一次promise的**函式,推入到queue屬性裡,以供deffered延遲物件使用。

var deferred = function();

deferred.prototype.resolve = function(data)}}

};deferred.prototype.reject = function(err)}}

};deferred.prototype.makenoderesolver = function()

};

這裡,和以往一樣,每乙個deferred物件都會有乙個promise物件。並且重新定義了resolvereject的實現,不再和以往一樣,簡單的通過觸發事件實現。我們仔細分析一下,到底deffered物件的方法做了些什麼。我們就取其中乙個resolve來看,首先我們將佇列promise的**佇列queue最前端的handler推出來,若存在就執行**。若**執行的結果是乙個新的promise(我們通過ispromise屬性判斷),我們就會進行乙個替換。這裡是實現的關鍵,我們將原來那個promise的queue屬性存到新的新的promise上,然後將deferred物件當前的promise變成新的promise,最後返回出來。通過這一系列的操作,我們就可以將**佇列進行傳遞,並實現鏈式呼叫。

--------hello.txt---------

data.json

--------data.json---------

--------**應用---------

var fs = require('fs');

var readfile = function(file);

var readjson = function(file));

return deferred.promise;

};readfile('hello.txt').then(function(file)).then(function(data));

// 或者利用更簡潔的特性

readfile('hello.txt').then(readjson).then(function(data));

最後這段**是我們多非同步並行佇列的實際應用。我們定義了兩個promise化的非同步方法,乙個是readfile,乙個readjson。我們的readjson函式是依賴readfile的結果的,最後我們一樣實現了需求。我們這次也僅僅是研究原理實現的**,是不成熟的。在實際應用中,還是需要借助成熟的框架q.js等。

我們可以發現,為了使**實現promise,我們需要為現有的非同步api都進行一次封裝。為了某些特殊情況,我們可以自己動手用promise/deferred模式,進行手動封裝實現功能。然後很多現有的api,我們是可以從中抽象出相同的部分,借助函式柯里化,進行批量promise轉化的。

return function();

};var fs = require('fs');

到此,promise三部曲,總算是講完了。在我總結寫blog時,也是做了比較多的思考,有些地方也可能表意不清。我們知道其實promise,其實是另一種形式的**,只是它的形式我們更喜歡,也更自然。我們唯一會煩惱的是,我們需要為不同場景的非同步api進行promise化。但是為了更好的控制,我認為也是值得嘗試的。promise單獨使用,並不能體現它強大的地方。因為接下來我們會講promise和generator配合,展現強大的非同步程式設計能力。

手寫乙個Promise(3)

then還沒有寫好。then的鏈式處理我們要對reject做一定的修改。if this status eswang.fufilled catch error 我們可以看到,fufilled狀態中,catch的reject使用的是新new的reject,而不是then中的函式引數。同樣需要這樣操作的還...

Promise 非同步程式設計

promise 是非同步程式設計的解決方案,他代表承諾,便是一定會丟擲兩種狀態,狀態一經確定就不會改變 編譯成功 resolve value 為 必選 編譯失敗 reject error 可選 使用then 接收正確的丟擲 then 後面接 catch function error 可以簡寫為fun...

Promise非同步程式設計

當我們用 ajax去請求有依賴的多個資料的時候,編寫會形成漏斗形狀的結構,可讀性差,可以使用es6提供的promise promise概述 promise是非同步程式設計的一種解決方案,從語法上講,promise是乙個物件,從它可以獲得非同步操作的訊息 使用promise有以下好處 可以避免多層非同...