JavaScript 異步進(jìn)化說(shuō)

原文鏈接:http://www.luckyjing.com/posts/js/async.html

本期的關(guān)鍵字為:callback timeout Promise generator async
每一個(gè)切圖仔們都在異步的路上掙扎過(guò)溜嗜,前端世界變化頻繁只损,全世界的各種大神也在不斷地在豐富著異步輪子调衰,從草案到標(biāo)準(zhǔn)也經(jīng)歷了相當(dāng)長(zhǎng)的一段時(shí)間,這篇文章帶你清晰地遍歷一遍異步的寫法,從回調(diào)地獄到優(yōu)雅“同步”巨朦。

文章主線

  • 本文剛開始介紹最常見(jiàn)的異步函數(shù)回調(diào)執(zhí)行的形式送矩,并介紹Async庫(kù)進(jìn)行異步寫法的改進(jìn)。
  • 隨后介紹ES6規(guī)范里面的Promise蝌以,它是接下來(lái)的異步改進(jìn)形式的基礎(chǔ)炕舵。
  • 接下來(lái)為ES6規(guī)范里的Genetator,它提供了一個(gè)可以暫停與恢復(fù)的內(nèi)部迭代器,本身并不具有改進(jìn)異步的特點(diǎn)跟畅,但是可以使用co庫(kù)結(jié)合Promise實(shí)現(xiàn)優(yōu)雅的異步寫法咽筋。
  • 最后為ES7中的async和await關(guān)鍵字,它相當(dāng)于內(nèi)部實(shí)現(xiàn)了co庫(kù)的封裝徊件,所以使用起來(lái)也與co庫(kù)更加相似奸攻,只不過(guò)相對(duì)于Generator里面的yield關(guān)鍵字,更具有語(yǔ)義化虱痕。

開胃菜

異步線程總是在JavaScript主線程空閑后(也就是for循環(huán)執(zhí)行完畢)進(jìn)行執(zhí)行睹耐,所以我們會(huì)觀察到in loop會(huì)先于任何console.log(i)執(zhí)行,而且對(duì)于變量i創(chuàng)建了閉包部翘,所以最終的輸出為3個(gè)3

for (var i = 0; i < 3; i++) {
  console.log('in loop');
  setTimeout(function () {    
    console.log(i);
  }, 0);
}

異步三大情景

情景一

情景二

情景三

第一階段:回調(diào)與async庫(kù)

材料準(zhǔn)備:

  • 安裝async庫(kù):npm install async --save
  • 異步函數(shù)硝训,使用fs.readFile進(jìn)行演示
  • 準(zhǔn)備要讀取的相關(guān)文件,使用a.jsonb.json進(jìn)行演示

如果使用傳統(tǒng)的回調(diào)方式新思,在異步任務(wù)數(shù)量增加時(shí)窖梁,便無(wú)法控制,下圖展示了僅僅二層的異步回調(diào):

這個(gè)時(shí)候表牢,我們可以使用async庫(kù)進(jìn)行上述三大情景的執(zhí)行窄绒。

parallel,并行且無(wú)關(guān)的任務(wù)

準(zhǔn)備一系列任務(wù)數(shù)組,并且將數(shù)據(jù)傳入cb參數(shù)崔兴,隨后在cb中取得這些數(shù)據(jù)組成的數(shù)組彰导。

如果在執(zhí)行中某個(gè)任務(wù)拋出了異常,將不會(huì)再啟動(dòng)還未開始的任務(wù)敲茄,但是已經(jīng)開始的任務(wù)不受影響

series,串行且無(wú)關(guān)的任務(wù)

series更像同一時(shí)間只可以執(zhí)行一個(gè)任務(wù)的parallel位谋,所以語(yǔ)法上和parallel相同。

如果在執(zhí)行中某個(gè)任務(wù)拋出了異常堰燎,將不會(huì)再啟動(dòng)后續(xù)所有任務(wù)掏父。

waterfall,串行且相關(guān)的任務(wù)

waterfall瀑布式的任務(wù),會(huì)按次序一個(gè)個(gè)執(zhí)行秆剪,但是數(shù)據(jù)的流向并不是終點(diǎn)的callback赊淑,而是傳遞給下一個(gè)爵政,所以更像是流水線作業(yè),把數(shù)據(jù)的鍋拋來(lái)拋去陶缺。

第二階段:Promise

材料準(zhǔn)備:

  • Node環(huán)境
  • 瀏覽器端使用babel

Promise采用的是你先去執(zhí)行钾挟,隨后通知我,我來(lái)處理怎么做的形式饱岸,可以通過(guò)then方法串起來(lái)掺出,then方法依然返回的是一個(gè)新的Promise實(shí)例,它的狀態(tài)取決于then方法體內(nèi)的返回值苫费,如果是一般類型汤锨,則直接轉(zhuǎn)到resolve狀態(tài),如果是Promise對(duì)象百框,那么會(huì)轉(zhuǎn)入對(duì)這個(gè)新的Promise的處理中來(lái)闲礼。

parallel

series 與 waterfall

我們可以發(fā)現(xiàn),使用了Promise之后琅翻,寫法格式上的主動(dòng)權(quán)交由我們控制位仁,所以實(shí)現(xiàn)series只需要自己模擬情景即可。

let result=[];
p1.then(data=>{
    result.push(data);    //可以將這里的data傳入第二個(gè)Promise生成對(duì)象方椎,即符合了waterfall情景       
    return p2;
}).then(data=>{
    result.push(data);
}).then(()=>{    
  console.log(result);
});

第三階段:Generator

材料準(zhǔn)備:

  • Node環(huán)境
  • 瀏覽器端使用babel

具體的Generator的語(yǔ)法可以參考阮一峰的《ECMAScript 6 入門》聂抢,主要講述結(jié)合co庫(kù)進(jìn)行異步流程控制。

使用co庫(kù)可以寫出非常便捷的“同步”的異步代碼棠众。

也可以使用一個(gè)數(shù)組去做并行的異步:

co(function*(){    
  return yield [
        readFile('data/a.json'),
        readFile('data/b.json')
    ]
}).then(res=>{
    log(res);
})

在這里再給大家說(shuō)一下co庫(kù)的基本原理琳疏,首先,我們先知道一下當(dāng)yield一個(gè)Promise對(duì)象會(huì)怎樣闸拿,自己在控制臺(tái)輸出后會(huì)發(fā)現(xiàn)會(huì)返回一個(gè)Promise對(duì)象空盼,狀態(tài)為Pending,而不是等Promise運(yùn)行到resolve或者reject后再執(zhí)行到yield新荤,那么co庫(kù)的基本原理便是如此揽趾,它會(huì)在每一個(gè)yield暫停后,將返回的對(duì)象包裝成一個(gè)Promise苛骨,隨即等Promise狀態(tài)到達(dá)終點(diǎn)時(shí)篱瞎,再去激活原來(lái)函數(shù)的執(zhí)行,直到gen.next()返回done為止痒芝,終止函數(shù)俐筋,并返回。

co原理

第四階段:async & await

材料準(zhǔn)備:

  • Node環(huán)境
  • babelbabel-preset-stage-3

當(dāng)嘗試了co庫(kù)之后严衬,再來(lái)看ES7里面的關(guān)鍵字的話澄者,就非常好理解了,上圖:

可以發(fā)現(xiàn),寫法上幾乎和co庫(kù)一模一樣粱挡,只不過(guò)使用了更加語(yǔ)義化的關(guān)鍵字赠幕,也不用引入外來(lái)庫(kù),但是使用的基礎(chǔ)依然是Promise對(duì)象抱怔,所以對(duì)于Promise劣坊,一定要好好地理解。

總結(jié)

JavaScript在異步流程控制的過(guò)程中屈留,經(jīng)驗(yàn)豐富的先驅(qū)者們創(chuàng)造了許多輪子,可供選擇的也有很多测蘑,但是基本思路都和Promise相關(guān)灌危,所以玩轉(zhuǎn)異步的基礎(chǔ)便是掌握好Promise,靜靜地等待編寫ES6/7不再需要轉(zhuǎn)換器時(shí)代的到來(lái)碳胳。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末勇蝙,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子挨约,更是在濱河造成了極大的恐慌味混,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诫惭,死亡現(xiàn)場(chǎng)離奇詭異翁锡,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)夕土,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門馆衔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人怨绣,你說(shuō)我怎么就攤上這事角溃。” “怎么了篮撑?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵减细,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我赢笨,道長(zhǎng)未蝌,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任质欲,我火速辦了婚禮树埠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘嘶伟。我一直安慰自己怎憋,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著绊袋,像睡著了一般毕匀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上癌别,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天皂岔,我揣著相機(jī)與錄音,去河邊找鬼展姐。 笑死躁垛,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的圾笨。 我是一名探鬼主播教馆,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼擂达!你這毒婦竟也來(lái)了土铺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤板鬓,失蹤者是張志新(化名)和其女友劉穎悲敷,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俭令,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡后德,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了唤蔗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片探遵。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖妓柜,靈堂內(nèi)的尸體忽然破棺而出箱季,到底是詐尸還是另有隱情,我是刑警寧澤棍掐,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布藏雏,位于F島的核電站,受9級(jí)特大地震影響作煌,放射性物質(zhì)發(fā)生泄漏掘殴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一粟誓、第九天 我趴在偏房一處隱蔽的房頂上張望奏寨。 院中可真熱鬧,春花似錦鹰服、人聲如沸病瞳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)套菜。三九已至亲善,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間逗柴,已是汗流浹背蛹头。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留戏溺,地道東北人渣蜗。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像旷祸,于是被迫代替她去往敵國(guó)和親袍睡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

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

  • 異步編程對(duì)JavaScript語(yǔ)言太重要肋僧。Javascript語(yǔ)言的執(zhí)行環(huán)境是“單線程”的,如果沒(méi)有異步編程控淡,根本...
    呼呼哥閱讀 7,301評(píng)論 5 22
  • 本文的示例代碼參考這里的async 目錄 引言 callbackasync ?PromisePromise對(duì)象bl...
    諾之林閱讀 499評(píng)論 1 5
  • 弄懂js異步 講異步之前嫌吠,我們必須掌握一個(gè)基礎(chǔ)知識(shí)-event-loop。 我們知道JavaScript的一大特點(diǎn)...
    DCbryant閱讀 2,706評(píng)論 0 5
  • 單線程與異步 Javascript是單線程運(yùn)行掺炭、支持異步機(jī)制的語(yǔ)言辫诅。進(jìn)入正題之前,我們有必要先理解這種運(yùn)行方式涧狮。 ...
    貝聊科技閱讀 621評(píng)論 0 0
  • 本文首發(fā)在個(gè)人博客:http://muyunyun.cn/posts/7b9fdc87/ 提到 Node.js, ...
    牧云云閱讀 1,679評(píng)論 0 3