Nodejs 異步編程解決方案

1. PubSub事件

事件監(jiān)聽模式是一種廣泛應(yīng)用于異步編程的解決方案铣缠,是回調(diào)函數(shù)的事件化,又稱發(fā)布訂閱模式。
關(guān)于發(fā)布訂閱的實(shí)現(xiàn)蝗蛙,可以看我之前的另外一篇文章聊聊設(shè)計(jì)模式(1):發(fā)布訂閱模式

Node中的發(fā)布訂閱模式

Node自身提供的events模塊是發(fā)布訂閱的一個(gè)基本實(shí)現(xiàn)蝇庭,相較于瀏覽器的事件機(jī)制,它更為簡(jiǎn)單:不存在事件冒泡捡硅,也不存在preventDefault(),stopImmediatePropagation等控制事件傳遞的方法遗契。它具有emit,on,removeListener,once,removeAllListener等方法。
訂閱事件on就是一個(gè)高階函數(shù),發(fā)布訂閱模式可以實(shí)現(xiàn)一個(gè)事件與多個(gè)回調(diào)函數(shù)之間的關(guān)聯(lián)病曾,這些回調(diào)函數(shù)又可以稱為事件偵聽器牍蜂。emit發(fā)布事件后,消息會(huì)傳給當(dāng)前函數(shù)的所有偵聽器執(zhí)行泰涂。
發(fā)布訂閱模式可用于解耦業(yè)務(wù)邏輯鲫竞,將不變的內(nèi)容封裝在組件內(nèi)部,將容易變化的暴露給外部處理逼蒙。另一個(gè)角度看从绘,發(fā)布訂閱模式也是一種鉤子(hock)的機(jī)制,利用鉤子導(dǎo)出內(nèi)部數(shù)據(jù)或者狀態(tài)給外部調(diào)用者是牢。node中很多對(duì)象大多具有黑盒的效用僵井,如果我們不通過鉤子的形式,很難獲取對(duì)象在運(yùn)行期間的中間值或者內(nèi)部狀態(tài)驳棱∨玻可以使編程者不再關(guān)注組件是如何啟動(dòng)的,只需關(guān)注在事件點(diǎn)上社搅。HTTP 請(qǐng)求便是常見的應(yīng)用場(chǎng)景驻债。

var options = {
    host: 'www.google.com',
    port: 80,
    path: '/upload',
    method: 'POST'
};
var req = http.request(options, function (res) {
    console.log('STATUS: ' + res.statusCode);
    console.log('HEADERS: ' + JSON.stringify(res.headers));
    res.setEncoding('utf8');
    res.on('data', function (chunk) {
        console.log('BODY: ' + chunk);
    });
});
req.on('error', function (e) {
    console.log('problem with request: ' + e.message);
});
// write data to request body
req.write('data\n');
req.write('data\n');
req.end();

在這段HTTP request的代碼中,程序員只需要將視線放在error形葬,data這些業(yè)務(wù)事件點(diǎn)即可合呐,至于內(nèi)部的流程如何,無(wú)需過于關(guān)注笙以。
Node為發(fā)布訂閱模式做了特殊的優(yōu)化淌实,下面為具體兩個(gè)細(xì)節(jié)點(diǎn):

  1. 如果一個(gè)事件添加了超過十個(gè)監(jiān)聽器,將會(huì)收到一個(gè)警告猖腕,調(diào)用emmiter.setMaxListener(0)可以將限制去掉
  2. 為了異常處理EventEmmiter對(duì)象對(duì)error事件做了特殊處理拆祈,如果觸發(fā)了error事件,會(huì)檢查是否對(duì)error事件添加了事件監(jiān)聽谈息。如果添加了缘屹,就交給該偵聽器,否則這個(gè)錯(cuò)誤會(huì)作為異常拋出侠仇。如果外部沒有捕獲這個(gè)異常,將會(huì),將會(huì)引起線程退出逻炊。

繼承events模塊

var events = require('events');
function Stream(){
events.EventEmitter.call(this);
}
util.inherits(Stream, events.EventEmitter)

事件隊(duì)列解決雪崩

利用once()方法互亮,將所有回調(diào)都?jí)喝胧录?duì)列,利用只執(zhí)行一次就會(huì)將監(jiān)視移除余素,保證每一個(gè)回調(diào)只執(zhí)行一次

多異步之間的協(xié)作

類似promise中的race()方法豹休,實(shí)現(xiàn)就是引入一個(gè)哨兵變量,利用偏函數(shù)處理哨兵變量和偏函數(shù)之間的關(guān)系桨吊。

2. Promise/Deffered模式

Promise 是異步編程的一種解決方案威根,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強(qiáng)大。它由社區(qū)最早提出和實(shí)現(xiàn)视乐,ES6 將其寫進(jìn)了語(yǔ)言標(biāo)準(zhǔn)洛搀,統(tǒng)一了用法,原生提供了Promise對(duì)象佑淀。
所謂Promise留美,簡(jiǎn)單說(shuō)就是一個(gè)容器,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果伸刃。從語(yǔ)法上說(shuō)谎砾,Promise 是一個(gè)對(duì)象,從它可以獲取異步操作的消息捧颅。Promise 提供統(tǒng)一的 API景图,各種異步操作都可以用同樣的方法進(jìn)行處理。
Promise對(duì)象有以下兩個(gè)特點(diǎn)碉哑。
(1)對(duì)象的狀態(tài)不受外界影響症歇。Promise對(duì)象代表一個(gè)異步操作,有三種狀態(tài):pending(進(jìn)行中)谭梗、fulfilled(已成功)和rejected(已失斖睢)。只有異步操作的結(jié)果激捏,可以決定當(dāng)前是哪一種狀態(tài)设塔,任何其他操作都無(wú)法改變這個(gè)狀態(tài)。這也是Promise
這個(gè)名字的由來(lái)远舅,它的英語(yǔ)意思就是“承諾”闰蛔,表示其他手段無(wú)法改變。
(2)一旦狀態(tài)改變图柏,就不會(huì)再變序六,任何時(shí)候都可以得到這個(gè)結(jié)果。Promise
對(duì)象的狀態(tài)改變蚤吹,只有兩種可能:從pending變?yōu)閒ulfilled和從pending變?yōu)閞ejected例诀。只要這兩種情況發(fā)生随抠,狀態(tài)就凝固了,不會(huì)再變了繁涂,會(huì)一直保持這個(gè)結(jié)果拱她,這時(shí)就稱為 resolved(已定型)。如果改變已經(jīng)發(fā)生了,你再Promise對(duì)象添加回調(diào)函數(shù),也會(huì)立即得到這個(gè)結(jié)果瞻润。這與事件(Event)完全不同永乌,事件的特點(diǎn)是,如果你錯(cuò)過了它,再去監(jiān)聽,是得不到結(jié)果的。
注意敞咧,為了行文方便,本章后面的resolved統(tǒng)一只指fulfilled狀態(tài)倔矾,不包含rejected狀態(tài)妄均。
有了Promise對(duì)象,就可以將異步操作以同步操作的流程表達(dá)出來(lái)哪自,避免了層層嵌套的回調(diào)函數(shù)丰包。此外,Promise
對(duì)象提供統(tǒng)一的接口壤巷,使得控制異步操作更加容易邑彪。
Promise也有一些缺點(diǎn)。首先胧华,無(wú)法取消Promise寄症,一旦新建它就會(huì)立即執(zhí)行,無(wú)法中途取消矩动。其次有巧,如果不設(shè)置回調(diào)函數(shù),Promise內(nèi)部拋出的錯(cuò)誤悲没,不會(huì)反應(yīng)到外部篮迎。第三,當(dāng)處于pending狀態(tài)時(shí)示姿,無(wú)法得知目前進(jìn)展到哪一個(gè)階段(剛剛開始還是即將完成)甜橱。
如果某些事件不斷地反復(fù)發(fā)生,一般來(lái)說(shuō)栈戳,使用 Stream 模式是比部署Promise
更好的選擇岂傲。

上面是阮一峰ES6標(biāo)準(zhǔn)教程中關(guān)于Promise的定義,Promise/Deferred模式包含兩部分子檀,即是PromiseDeferred.
看了promise的介紹镊掖,還是感覺不夠深入乃戈,這個(gè)在解決異步問題上是一個(gè)很好的解決方案,所以詳細(xì)看一下堰乔,順便按照自己的思路實(shí)現(xiàn)一個(gè)簡(jiǎn)單的Promise偏化。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末脐恩,一起剝皮案震驚了整個(gè)濱河市镐侯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌驶冒,老刑警劉巖苟翻,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異骗污,居然都是意外死亡崇猫,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門需忿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)诅炉,“玉大人,你說(shuō)我怎么就攤上這事屋厘√樯眨” “怎么了?”我有些...
    開封第一講書人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵汗洒,是天一觀的道長(zhǎng)议纯。 經(jīng)常有香客問我,道長(zhǎng)溢谤,這世上最難降的妖魔是什么瞻凤? 我笑而不...
    開封第一講書人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮世杀,結(jié)果婚禮上阀参,老公的妹妹穿的比我還像新娘。我一直安慰自己瞻坝,他們只是感情好蛛壳,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著湿镀,像睡著了一般炕吸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上勉痴,一...
    開封第一講書人閱讀 51,775評(píng)論 1 307
  • 那天赫模,我揣著相機(jī)與錄音,去河邊找鬼蒸矛。 笑死瀑罗,一個(gè)胖子當(dāng)著我的面吹牛胸嘴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播斩祭,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼劣像,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了摧玫?” 一聲冷哼從身側(cè)響起耳奕,我...
    開封第一講書人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎诬像,沒想到半個(gè)月后屋群,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡坏挠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年芍躏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片降狠。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡对竣,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出榜配,到底是詐尸還是另有隱情否纬,我是刑警寧澤,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布芥牌,位于F島的核電站烦味,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏壁拉。R本人自食惡果不足惜谬俄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望弃理。 院中可真熱鬧溃论,春花似錦、人聲如沸痘昌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)辆苔。三九已至算灸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間驻啤,已是汗流浹背菲驴。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留骑冗,地道東北人赊瞬。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓先煎,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親巧涧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子薯蝎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

推薦閱讀更多精彩內(nèi)容

  • 弄懂js異步 講異步之前,我們必須掌握一個(gè)基礎(chǔ)知識(shí)-event-loop谤绳。 我們知道JavaScript的一大特點(diǎn)...
    DCbryant閱讀 2,712評(píng)論 0 5
  • 你不知道JS:異步 第三章:Promises 在第二章占锯,我們指出了采用回調(diào)來(lái)表達(dá)異步和管理并發(fā)時(shí)的兩種主要不足:缺...
    purple_force閱讀 2,070評(píng)論 0 4
  • 你不知道JS:異步 第三章:Promises 接上篇3-1 錯(cuò)誤處理(Error Handling) 在異步編程中...
    purple_force閱讀 1,398評(píng)論 0 2
  • Javascript語(yǔ)言將任務(wù)的執(zhí)行模式分成兩種:同步(Synchronous)和異步(Asynchronous)...
    Sachie閱讀 390評(píng)論 0 0
  • 不愛這個(gè)詞 卻又總放在嘴邊 無(wú)它 這詞太過毒辣 不適合太過年輕的我們 有人為此犧牲幾十歲后的人生 苦苦支撐整個(gè)家族...
    布老頭和他的家人們閱讀 284評(píng)論 0 0