成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

簡(jiǎn)單理解Javascript的各種異步流程控制方法

makeFoxPlay / 2398人閱讀

摘要:所以僅用于簡(jiǎn)化理解,快速入門(mén),依然需要閱讀有深入研究的文章來(lái)加深對(duì)各種異步流程控制的方法的掌握。

原文地址:http://zodiacg.net/2015/08/javascript-async-control-flow/

隨著ES6標(biāo)準(zhǔn)逐漸成熟,利用Promise和Generator解決回調(diào)地獄問(wèn)題的話題一直很熱門(mén)。但是對(duì)解決流程控制/回調(diào)地獄問(wèn)題的各種工具認(rèn)識(shí)仍然比較麻煩。最近兩天看了很多文章,想出幾個(gè)場(chǎng)景把各種異步流程方式類(lèi)比一下,希望能有助于理解他們的實(shí)現(xiàn)。

需要說(shuō)明的是類(lèi)比只能反映被類(lèi)比的事物的一個(gè)方面,必然有其反映不到的部分,不能完全以類(lèi)比來(lái)理解各種異步控制的本質(zhì)。所以僅用于簡(jiǎn)化理解,快速入門(mén),依然需要閱讀有深入研究的文章來(lái)加深對(duì)各種異步流程控制的方法的掌握。

文章中沒(méi)有嚴(yán)格使用Node.js核心模塊的函數(shù)名,而是偽造的函數(shù)名來(lái)方便在各種方式下保持一致性和簡(jiǎn)化書(shū)寫(xiě)。

同步

從最簡(jiǎn)單的同步開(kāi)始。以一段經(jīng)典的代碼為例吧,傳入文件名,從文件中讀取內(nèi)容并按JSON格式解析,把其中的一部分內(nèi)容發(fā)還給用戶。

function foo(filename){
    var file = readFile(filename);
    var json = parseJSON(file);
    return json.someContent;
}

var resultA=foo("first.json");
var resultB=foo("second.json");

其中readFileparseJSON顯而易見(jiàn)是同步、阻塞的函數(shù)。

我們構(gòu)造這樣一個(gè)場(chǎng)景,M(ain)代表著解釋引擎的主線程,坐在柜臺(tái)前等待用戶提交請(qǐng)求。

來(lái)了兩個(gè)用戶A和用戶B,用戶A排在前面。

用戶A: 你好,我要讀文件first.json。
M:好的你等一下我去拿。
【M離開(kāi)了柜臺(tái)去拿文件】
M:好的我回來(lái)了,這是你要的first.json的內(nèi)容。然后呢?
用戶A:然后把內(nèi)容按JSON解析一下。
M:你等等我去解析一下。
【M離開(kāi)了柜臺(tái)去解析文件內(nèi)容】
M:好了解析完了,然后呢?
用戶A:我要里面的someContent部分。
M:給你。再見(jiàn)。

用戶B:你好,我要讀文件second.json。
…………

可以看到同步阻塞顧名思義,操作一步一步進(jìn)行,遇到IO操作每一步都要等待,用戶A不處理完,用戶B也進(jìn)不來(lái)。

經(jīng)典回調(diào)方式

仍然是這個(gè)需求,這次的代碼就比較像Node.js里的常見(jiàn)形式了,此處為了簡(jiǎn)單忽略了err。由于回調(diào)套回調(diào),縮進(jìn)如同金字塔,被稱(chēng)作回調(diào)地獄。當(dāng)然回調(diào)地獄遠(yuǎn)不是一個(gè)縮進(jìn)金字塔那么簡(jiǎn)單。

function foo(filename, cb){
    readFile(filename,function(file){
        parseJSON(file,function(json){
            cb(json.someContent);
        });
    });
}

foo("first.json",cbA);
foo("second.json",cbB);

依然是來(lái)了兩個(gè)用戶A和用戶B

用戶A:你好,我要讀文件first.json,按JSON解析后把里面的someContent寄往cbA發(fā)回給我。
M:好的。
【M開(kāi)始寫(xiě)信,信封上寫(xiě)上文件讀取處readFile,拿出一張信紙寫(xiě)到:“讀取first.json,然后內(nèi)容放進(jìn)后附信封中寄出”?!?
【M又拿出一個(gè)信封,寫(xiě)上JSON解析處parseJSON,信紙上寫(xiě)到“把給你的file按JSON解析,然后把里面的someContent放到所附信封里寄出”。】
【M又又拿出一個(gè)信封,寫(xiě)上cbA,然后把這個(gè)信封放進(jìn)了剛才的信封里,又把剛才的信封塞進(jìn)了第一個(gè)信封里?!?
【M把鼓鼓囊囊的信封扔到郵箱里就不管了】
M:下一位!
用戶B:你好……

寫(xiě)幾封信的時(shí)間比自己跑出去取文件要快的多。異步操作帶來(lái)的處理速度提升是顯而易見(jiàn)的。

但是為了保證業(yè)務(wù)流程的銜接,信里面就包含了后續(xù)一切需要進(jìn)行的操作,層層包裹。第一封信寄出,M就既無(wú)從得知信走到了何處,也無(wú)法控制readFileparseJSON是不是如自己所想寄出了給他的信封,有沒(méi)有私自復(fù)印了多寄了一兩封。

這才是回調(diào)地獄真正危險(xiǎn)的地方,缺乏控制。

Promise

引入Promise之后,很多人就以為能解決回調(diào)地獄了,其實(shí)不然。在某些場(chǎng)景下只是讓縮進(jìn)好看了一點(diǎn)而已。有些場(chǎng)景下縮進(jìn)也沒(méi)法好看,需要書(shū)寫(xiě)的回調(diào)不僅不會(huì)減少還會(huì)增多。

function foo(filename,cb){
    readFile(filename)
    .then(parseJSON(file))
    .then(function(json){
    cb(json.someContent)});
}

foo("first.json",cbA);
foo("second.json",cbB);

當(dāng)然這里面的readFileparseJSON已經(jīng)是Promise化了的。

依然是來(lái)了兩個(gè)用戶A和用戶B

用戶A:你好,我要讀文件first.json,按JSON解析后把里面的someContent寄往cbA發(fā)回給我。
M:好的。
【M叫來(lái)了一個(gè)辦事員小P】
M:小P你聽(tīng)好,先去找readFile讀取first.json,然后把內(nèi)容給parseJSON讓他解析一下,最后把解析的內(nèi)容里的someContent寄給cb,懂了嗎?
P:我辦事你放心!
【小P離開(kāi)了柜臺(tái)】
M:下一位!
用戶B:你好……

小P是一位M信得過(guò)的辦事員,M相信他能夠挨個(gè)去找該找的部門(mén),不偷工減料也不毛手毛腳。讓小P去辦事比寄一封信靠譜的多,M依然能很快回過(guò)頭來(lái)繼續(xù)應(yīng)付下一個(gè)用戶請(qǐng)求。

當(dāng)然實(shí)際場(chǎng)景中雖然寫(xiě)的時(shí)候.then一下子連起來(lái)寫(xiě)完,并不是真的一下子把內(nèi)容都交給同一位小P/同一個(gè)Promise。更像是一個(gè)Promise公司,每個(gè)操作進(jìn)行完后都由一位Promise公司的辦事員進(jìn)行下一步操作。

Promise物如其名,使用Promise重要的就是Promise的可信性,比如Promise的狀態(tài)不可逆,比如fulfill回調(diào)只會(huì)被調(diào)用一次。Promise并不是回避書(shū)寫(xiě)回調(diào),而是用一種更可靠的方式來(lái)書(shū)寫(xiě)回調(diào)。

Co(Generator)

這里只談co不談Generator,是因?yàn)镚enerator并不是為解決異步流程控制而生的,而TJ大神用co把Generator和Thunk/Promise結(jié)合在一起提供了新的異步流程控制的方法。

var foo=co(function*(filename){
    var file = yield readFile(filename);
    var json = yield parseJSON(file);
    return json.someContent;
});

foo("first.json").then(cbA);
foo("second.json").then(cbB);

咦?這代碼看起來(lái)跟同步的怎么差不多。

這次我們換個(gè)方法描述,一樣是來(lái)了用戶A和用戶B,但是先從用戶A的視角來(lái)看這件事情。

用戶A: 你好,我要讀文件first.json。
M:好的你等一下我去拿。
【M離開(kāi)了柜臺(tái)】
M:我回來(lái)了,這是你要的first.json的內(nèi)容。然后呢?
用戶A:然后把內(nèi)容按JSON解析一下。
M:你等等我去解析一下。
【M離開(kāi)了柜臺(tái)】
M:好了解析完了,然后呢?
用戶A:我要里面的someContent部分。
M:給你。再見(jiàn)。

是不是看起來(lái)跟同步一模一樣?實(shí)際上從M的角度看這件事情呢?

用戶A: 你好,我要讀文件first.json。
M:好的你等一下我去拿。
【M離開(kāi)了柜臺(tái)】
M:小P來(lái)一下!去readFilefirst.json,回來(lái)叫我。
P:好的我這就去。
【M轉(zhuǎn)向了另一個(gè)柜臺(tái)窗口】
M:你好。
用戶B:你好,我要讀文件second.json。
…………
…………
P:M,first.json拿回來(lái)了。
【M轉(zhuǎn)向第一個(gè)柜臺(tái)】
M:我回來(lái)了,這是你要的first.json的內(nèi)容。然后呢?
用戶A:然后把內(nèi)容按JSON解析一下。
M:你等等我去解析一下。
【M離開(kāi)了柜臺(tái)】
M:小P來(lái)一下!去parseJSON把這堆東西解析一下,回來(lái)叫我。
P:好的我這就去。
【M轉(zhuǎn)向了另一個(gè)柜臺(tái)窗口】
…………
…………

真相大白了,M并沒(méi)有親自去拿文件解析JSON,而是叫來(lái)了任勞任怨的小P干活,自己在用戶A面前偽裝成被占用了所有的時(shí)間的樣子,其實(shí)偷偷去接待別的用戶了。

利用Generator可以用yield中斷執(zhí)行,再在外部通過(guò)next喚醒繼續(xù)執(zhí)行的特性,co把Generator的next寫(xiě)到Promise的then里面從而實(shí)現(xiàn)循環(huán)調(diào)用。使用了co之后,代碼看起來(lái)跟同步非常相像,寫(xiě)起來(lái)符合人正常的同步思維,甚至可以使用同步的流程控制語(yǔ)句比如for。但是執(zhí)行起來(lái)卻能充分利用異步帶來(lái)的性能優(yōu)勢(shì)。

順便提一句,co看起來(lái)已經(jīng)非常像async/await方式了。Node.js中同樣近似于async/await方式的還有asyncawait庫(kù),它不依賴(lài)generator而是依賴(lài)于node-fiber,看名字大概就是Node里的一個(gè)纖程的實(shí)現(xiàn)吧。由于不需要generator,對(duì)于諸如Coffescript和Typescript類(lèi)的語(yǔ)言支持非常好。

以上就是對(duì)Javascript中最近常討論的幾種異步流程控制的簡(jiǎn)單類(lèi)比說(shuō)明。這種理解方式非常粗淺,而且有很多問(wèn)題并不像上面寫(xiě)的那樣那么簡(jiǎn)單。要想使用好異步,還是要多讀一些更為深入的文章。

參考資料

Promises and Generators: Control Flow Utopia

Promises/A+

Managing Node.js Callback Hell with Promises, Generators and Other Approaches

Replacing callbacks with ES6 Generators

getiblog: Promises

異步流程控制:7 行代碼學(xué)會(huì) co 模塊

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/85899.html

相關(guān)文章

  • JavaScript 異步

    摘要:從最開(kāi)始的到封裝后的都在試圖解決異步編程過(guò)程中的問(wèn)題。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。寫(xiě)一個(gè)符合規(guī)范并可配合使用的寫(xiě)一個(gè)符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來(lái)處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問(wèn)題描述 在開(kāi)發(fā)過(guò)程中,遇到一個(gè)需求:在系統(tǒng)初始化時(shí)通過(guò)http獲取一個(gè)第三方服務(wù)器端的列表,第三方服務(wù)器提供了一個(gè)接口,可通過(guò)...

    tuniutech 評(píng)論0 收藏0
  • javascript異步編程詳解

    摘要:在服務(wù)器端,異步模式甚至是唯一的模式,因?yàn)閳?zhí)行環(huán)境是單線程的,如果允許同步執(zhí)行所有請(qǐng)求,服務(wù)器性能會(huì)急劇下降,很快就會(huì)失去響應(yīng)。第三是,捕捉不到他的錯(cuò)誤異步編程方法回調(diào)函數(shù)這是異步編程最基本的方法。 前言 你可能知道,Javascript語(yǔ)言的執(zhí)行環(huán)境是單線程(single thread)。所謂單線程,就是指一次只能完成一件任務(wù)。如果有多個(gè)任務(wù),就必須排隊(duì),前面一個(gè)任務(wù)完成,再執(zhí)行后面...

    huangjinnan 評(píng)論0 收藏0
  • 【全文】狼叔:如何正確學(xué)習(xí)Node.js

    摘要:感謝大神的免費(fèi)的計(jì)算機(jī)編程類(lèi)中文書(shū)籍收錄并推薦地址,以后在倉(cāng)庫(kù)里更新地址,聲音版全文狼叔如何正確的學(xué)習(xí)簡(jiǎn)介現(xiàn)在,越來(lái)越多的科技公司和開(kāi)發(fā)者開(kāi)始使用開(kāi)發(fā)各種應(yīng)用。 說(shuō)明 2017-12-14 我發(fā)了一篇文章《沒(méi)用過(guò)Node.js,就別瞎逼逼》是因?yàn)橛腥嗽谥跎虾贜ode.js。那篇文章的反響還是相當(dāng)不錯(cuò)的,甚至連著名的hax賀老都很認(rèn)同,下班時(shí)讀那篇文章,竟然坐車(chē)的還坐過(guò)站了。大家可以很...

    Edison 評(píng)論0 收藏0
  • 【全文】狼叔:如何正確學(xué)習(xí)Node.js

    摘要:感謝大神的免費(fèi)的計(jì)算機(jī)編程類(lèi)中文書(shū)籍收錄并推薦地址,以后在倉(cāng)庫(kù)里更新地址,聲音版全文狼叔如何正確的學(xué)習(xí)簡(jiǎn)介現(xiàn)在,越來(lái)越多的科技公司和開(kāi)發(fā)者開(kāi)始使用開(kāi)發(fā)各種應(yīng)用。 說(shuō)明 2017-12-14 我發(fā)了一篇文章《沒(méi)用過(guò)Node.js,就別瞎逼逼》是因?yàn)橛腥嗽谥跎虾贜ode.js。那篇文章的反響還是相當(dāng)不錯(cuò)的,甚至連著名的hax賀老都很認(rèn)同,下班時(shí)讀那篇文章,竟然坐車(chē)的還坐過(guò)站了。大家可以很...

    fengxiuping 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<