NodeJS中利用Promise來(lái)封裝異步函數(shù)
來(lái)源:易賢網(wǎng) 閱讀:865 次 日期:2015-02-27 11:13:48
溫馨提示:易賢網(wǎng)小編為您整理了“NodeJS中利用Promise來(lái)封裝異步函數(shù)”,方便廣大網(wǎng)友查閱!

這篇文章主要介紹了NodeJS中利用Promise來(lái)封裝異步函數(shù),使用統(tǒng)一的鏈?zhǔn)紸PI來(lái)擺脫多重回調(diào)的噩夢(mèng),非常的實(shí)用的小技能,希望小伙伴們能夠喜歡

在寫(xiě)Node.js的過(guò)程中,連續(xù)的IO操作可能會(huì)導(dǎo)致“金字塔噩夢(mèng)”,回調(diào)函數(shù)的多重嵌套讓代碼變的難以維護(hù),利用CommonJs的Promise來(lái)封裝異步函數(shù),使用統(tǒng)一的鏈?zhǔn)紸PI來(lái)擺脫多重回調(diào)的噩夢(mèng)。

Node.js提供的非阻塞IO模型允許我們利用回調(diào)函數(shù)的方式處理IO操作,但是當(dāng)需要連續(xù)的IO操作時(shí),你的回調(diào)函數(shù)會(huì)多重嵌套,代碼很不美觀,而且不易維護(hù),而且可能會(huì)有許多錯(cuò)誤處理的重復(fù)代碼,也就是所謂的“Pyramid of Doom”。

代碼如下:

step1(function (value1) {

step2(value1, function(value2) {

step3(value2, function(value3) {

step4(value3, function(value4) {

// Do something with value4

});

});

});

});

這其實(shí)就是Node.js的Control flow的問(wèn)題,對(duì)于這個(gè)問(wèn)題,解決方案都許多,比如利用async,或者eventProxy等,不過(guò)本文的主題是利用CommonJs規(guī)范中對(duì)Promise來(lái)解決這個(gè)問(wèn)題。

什么是Promise?

CommonJs的Promise規(guī)范有許多種,我們一般討論的是Promise/A+規(guī)范,它定義了Promise的基本行為。

Promise是一個(gè)對(duì)象,它通常代表一個(gè)在未來(lái)可能完成的異步操作。這個(gè)操作可能成功也可能失敗,所以一個(gè)Promise對(duì)象一般有3個(gè)狀態(tài):Pending,F(xiàn)ulfilled,Rejected。分別代表未完成、成功完成和操作失敗。一旦Promise對(duì)象的狀態(tài)從Pending變成Fulfilled或者Rejected任意一個(gè),它的狀態(tài)都沒(méi)有辦法再被改變。

一個(gè)Promise對(duì)象通常會(huì)有一個(gè)then方法,這個(gè)方法讓我們可以去操作未來(lái)可能成功后返回的值或者是失敗的原因。這個(gè)then方法是這樣子的:

promise.then(onFulfilled, onRejected)

顯而易見(jiàn)的是,then方法接受兩個(gè)參數(shù),它們通常是兩個(gè)函數(shù),一個(gè)是用來(lái)處理操作成功后的結(jié)果的,另一個(gè)是用來(lái)處理操作失敗后的原因的,這兩個(gè)函數(shù)的第一個(gè)參數(shù)分別是成功后的結(jié)果和失敗的原因。如果傳給then方法的不是一個(gè)函數(shù),那么這個(gè)參數(shù)會(huì)被忽略。

then方法的返回值是一個(gè)Promise對(duì)象,這一個(gè)特點(diǎn)允許我們鏈?zhǔn)秸{(diào)用then來(lái)達(dá)到控制流程的效果。這里有許多細(xì)節(jié)上的問(wèn)題,比如值的傳遞或者錯(cuò)誤處理等。Promise的規(guī)范是這樣定義的:

onFulfilled或者onRejected函數(shù)的返回值不是Promise對(duì)象,則該值將會(huì)作為下一個(gè)then方法中onFulfilled的第一個(gè)參數(shù),如果返回值是一個(gè)Promise對(duì)象,怎么then方法的返回值就是該P(yáng)romise對(duì)象

onFulfilled或者onRejected函數(shù)中如果有異常拋出,則該then方法的返回的Promise對(duì)象狀態(tài)轉(zhuǎn)為Rejected,如果該P(yáng)romise對(duì)象調(diào)用then,則Error對(duì)象會(huì)作為onRejected函數(shù)的第一個(gè)參數(shù)

如果Promise狀態(tài)變?yōu)镕ulfilled而在then方法中沒(méi)有提供onFulfilled函數(shù),則then方法返回的Promise對(duì)象狀態(tài)變?yōu)镕ulfilled且成功的結(jié)果為上一個(gè)Promise的結(jié)果,Rejected同理。

補(bǔ)充一句,onFulfilled和onRejected都是異步執(zhí)行的。

規(guī)范的實(shí)現(xiàn):q

上面講的是Promise的規(guī)范,而我們需要的是它的實(shí)現(xiàn),q是一個(gè)對(duì)Promise/A+有著較好實(shí)現(xiàn)規(guī)范的庫(kù)。

首先我們需要?jiǎng)?chuàng)建一個(gè)Promise對(duì)象,關(guān)于Promise對(duì)象創(chuàng)建的規(guī)范在Promise/B中,這里不做詳細(xì)的解釋?zhuān)苯由洗a。

代碼如下:

function(flag){

var defer = q.defer();

fs.readFile("a.txt", function(err, data){

if(err) defer.reject(err);

else defer.resolve(data);

});

return defer.promise;

}

多數(shù)Promise的實(shí)現(xiàn)在Promise的創(chuàng)建上大同小異,通過(guò)創(chuàng)建一個(gè)具有promise屬性的defer對(duì)象,如果成功獲取到值則調(diào)用defer.resolve(value),如果失敗,則調(diào)用defer.reject(reason),最后返回defer的promise屬性即可。這個(gè)過(guò)程可以理解為調(diào)用defer.resolve將Promise的狀態(tài)變成Fulfilled,調(diào)用defer.reject將Promise的狀態(tài)變成Rejected。

在面對(duì)一系列連續(xù)的異步方法時(shí),怎么利用Promise寫(xiě)出漂亮的代碼呢?看下下面的例子。

代碼如下:

promise0.then(function(result){

// dosomething

return result;

}).then(function(result) {

// dosomething

return promise1;

}).then(function(result) {

// dosomething

}).catch(function(ex) {

console.log(ex);

}).finally(function(){

console.log("final");

});

在上面的代碼中,then方法只接受OnFulfilled,而catch方法實(shí)際上就是then(null, OnRejected),這樣的話只要一系列異步方法只要始終是成功返回值的,那么代碼就會(huì)瀑布式的向下運(yùn)行,如果其中任意一個(gè)異步方法失敗或者發(fā)生異常,那么根據(jù)CommonJs的Promise規(guī)范,將執(zhí)行catch中的function。q還提供了finally方法,從字面上也很好理解,就是不論resolve還是reject,最終都會(huì)執(zhí)行finally中的function。

看上去似乎不錯(cuò),代碼更以維護(hù)且美觀了,那么如果希望并發(fā)呢?

代碼如下:

q.all([promise0, promise1, promise2]).spread(function(val0, val1, val2){

console.log(arguments);

}).then(function(){

console.log("done");

}).catch(function(err){

console.log(err);

});

q也為并發(fā)提供了api,調(diào)用all方法并傳遞一個(gè)Promise數(shù)組即可繼續(xù)使用then的鏈?zhǔn)斤L(fēng)格。還有像q.nfbind等可以將Node.js的原生API轉(zhuǎn)化成Promise來(lái)統(tǒng)一代碼格式也是挺好的。更多api在這里就不一一詳述了。

結(jié)論

本文主要介紹通過(guò)使用Promise來(lái)解決Node.js控制流問(wèn)題,但Promise也可同樣應(yīng)用于前端,EMCAScript6已經(jīng)提供了原生的API支持。需要指出的是Promise并不是唯一的解決方案,async也是一個(gè)很好的選擇,并且提供更友好的并發(fā)控制API,不過(guò)我覺(jué)得Promise在封裝具有異步方法的函數(shù)時(shí)更具優(yōu)勢(shì)。

好了,本文就先到這里了,希望對(duì)大家能夠有所幫助。

更多信息請(qǐng)查看IT技術(shù)專(zhuān)欄

更多信息請(qǐng)查看腳本欄目
易賢網(wǎng)手機(jī)網(wǎng)站地址:NodeJS中利用Promise來(lái)封裝異步函數(shù)
由于各方面情況的不斷調(diào)整與變化,易賢網(wǎng)提供的所有考試信息和咨詢(xún)回復(fù)僅供參考,敬請(qǐng)考生以權(quán)威部門(mén)公布的正式信息和咨詢(xún)?yōu)闇?zhǔn)!

2025國(guó)考·省考課程試聽(tīng)報(bào)名

  • 報(bào)班類(lèi)型
  • 姓名
  • 手機(jī)號(hào)
  • 驗(yàn)證碼
關(guān)于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡(jiǎn)要咨詢(xún) | 簡(jiǎn)要咨詢(xún)須知 | 加入群交流 | 手機(jī)站點(diǎn) | 投訴建議
工業(yè)和信息化部備案號(hào):滇ICP備2023014141號(hào)-1 云南省教育廳備案號(hào):云教ICP備0901021 滇公網(wǎng)安備53010202001879號(hào) 人力資源服務(wù)許可證:(云)人服證字(2023)第0102001523號(hào)
云南網(wǎng)警備案專(zhuān)用圖標(biāo)
聯(lián)系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢(xún)關(guān)注公眾號(hào):hfpxwx
咨詢(xún)QQ:526150442(9:00—18:00)版權(quán)所有:易賢網(wǎng)
云南網(wǎng)警報(bào)警專(zhuān)用圖標(biāo)