日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

異步編程之Generator(1)——領(lǐng)略魅力

系統(tǒng) 2586 0

異步編程系列教程:

  1. (翻譯)異步編程之Promise(1)——初見魅力
  2. 異步編程之Promise(2):探究原理
  3. 異步編程之Promise(3):拓展進(jìn)階
  4. 異步編程之Generator(1)——領(lǐng)略魅力
  5. 異步編程之Generator(2)——剖析特性
  6. 異步編程之co——源碼分析

為何使用Generator


回顧一下我們之前學(xué)習(xí)的promise。我們巧妙利用了 promise/deferred 模式,用鏈?zhǔn)浇Y(jié)構(gòu)代替了嵌套回調(diào)的結(jié)構(gòu),大大緩解了回調(diào)地獄。我們再來看看之前我們舉的那個異步串行隊(duì)列的例子吧!假設(shè)我們有一個 hello.txt ,里面存了一個JSON文件的文件名,我們需要得到JSON文件的message屬性的值。步驟如下:

  1. 讀取 hello.txt 文件
  2. 得到JSON文件名,再次讀取文件
  3. 得到JSON數(shù)據(jù)后,進(jìn)行JSON解析
  4. 獲得JSON的message屬性

Promise鏈?zhǔn)秸{(diào)用

這個例子我們之前也是舉過非常多次的,我們嘗試使用Promise鏈?zhǔn)浇Y(jié)構(gòu)完成:

    
      //這里的readFile已經(jīng)是promise化的異步API
readFile('hello.txt', 'utf-8')
    .then(function(filename){
        return readFile(filename, 'utf-8');
    })
    .then(JSON.parse)
    .then(function(data){
        console.log(data.message);
    })
    .catch(function(err){
        console.error(err.message);
    });
    
  

這樣一看下來,promise好像并沒有多大問題,思維是線性的,而且錯誤處理也很友好。我們只需要把上一層執(zhí)行后的結(jié)果通過 then() 傳到下一步執(zhí)行即可。嗯,但不得不說被鏈?zhǔn)浇Y(jié)構(gòu)束縛后,我們并沒有得到一種酣暢淋漓的編程體驗(yàn)。

同步API

我們要寫的爽,當(dāng)然是要將異步編程得到同步編程的體驗(yàn),這樣我們直接使用同步API看一下是怎樣的:

    
      var filename = fs.readFileSync('hello.txt', 'utf-8');
var json = fs.readFileSync(filename, 'utf-8');
console.log(JSON.parse(json).message);
    
  

同步的寫法清晰明了,而且更符合我們以往的編程習(xí)慣。但是同步API阻塞代碼這個弊病會在Javascript的單線程執(zhí)行中非常明顯。我們到底有沒有一種既可以非常接近同步編程的寫法,又可以異步不阻塞代碼執(zhí)行呢?既然問出這種問題,答案當(dāng)然是有的,就是今天的主角: Generator

Generator使用co寫法

Generator,顧名思義是一個構(gòu)造器,它本身是用來生成迭代器的。它是ES6的新東西,所以你為了使用它,需要在node中開啟harmony模式才能體驗(yàn)到它。

$ node --harmony

基于Generator,TJ大神做了一個 co 庫。 co 在最新的版本里,結(jié)合Generator和Promise改善了異步編程的體驗(yàn),也就是我們之前說的: 既可以同步,又不會阻塞

還是一樣的例子,我們結(jié)合promise的代碼和同步API的代碼對比看看:

    
      co(function* (){
    var filename = yield readFile('hello.txt', 'utf-8');
    var json = yield readFile(filename, 'utf-8');
    return JSON.parse(json).message;
}).then(console.log, console.error);
    
  

非常像有沒有,我們不再需要將每一次異步的結(jié)果都放在 then() 中進(jìn)行處理,我們可以通過類似于同步的寫法調(diào)用Promise異步API,大大提升編程體驗(yàn)。最后 co() 返回了一個promise對象,提供我們做最后的數(shù)據(jù)處理和錯誤處理。我們從同步API轉(zhuǎn)到 co ,僅僅需要做到以下幾點(diǎn):

  • co里面?zhèn)鞯暮瘮?shù)標(biāo)識符需要加上*號, function* 。這也就是Generator函數(shù)
  • 調(diào)用promise異步API之前,都要加上 yield 標(biāo)識符
  • 將需要做最后處理的數(shù)據(jù) return 出來,在 then() 中進(jìn)行處理即可

預(yù)習(xí)Generator


我們在舉完異步串行的例子后,這次的文章就接近尾聲了。最后我們可以大致了解一下 co 到底是如何運(yùn)作的呢?我們會在接下來的文章進(jìn)行深究,這一次就簡單說一說,你當(dāng)作預(yù)習(xí)就可以了:

Generator相關(guān)

  1. Generator生成迭代器后,等待迭代器的 next() 指令啟動。
  2. 啟動迭代器后,代碼會運(yùn)行到y(tǒng)ield處停止。并返回一個 {value: AnyType, done: Boolean} 對象, value 是這次執(zhí)行的結(jié)果, done 是迭代是否結(jié)束。并等待下一次的 next() 指令。
  3. next() 再次啟動后。若 done 屬性不為true,則可以繼續(xù)從上一次停止的地方繼續(xù)迭代。
  4. 一直重復(fù)2,3步驟,直到 done 為true。

co相關(guān)

  1. co內(nèi)部的迭代器對象是被封裝成Promise的。
  2. yield 后面跟的必須是一個promise化的異步API,所以 next() 得到的結(jié)果是一個promise對象。
  3. 若迭代沒有結(jié)束,則 co 會自動為該異步promise對象的 resolve 中,增添一個 next() 。通過前面的異步執(zhí)行完回調(diào)后,再調(diào)用 next() ,使迭代器的代碼不斷向前執(zhí)行。
  4. 若迭代結(jié)束,則直接調(diào)用整個迭代器對象的 resolve

總結(jié)

或許現(xiàn)在大家看的是一知半解,或許很興奮想知道更多相關(guān)的。若僅僅是想學(xué)會用co,我想上面的大概已經(jīng)足夠你看了。但是想更深入,你必須先弄懂promise的原理和Generator的相關(guān)特性。最后使用 co 庫一定會得心應(yīng)手。

接下來,我會先講一些關(guān)于Generator的相關(guān)特性,再配合之前說過的promise,深入到 co 的源碼學(xué)習(xí)中。

異步編程之Generator(1)——領(lǐng)略魅力


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 朝阳市| 微山县| 井冈山市| 绥江县| 枝江市| 芷江| 连城县| 乌拉特前旗| 喜德县| 南充市| 华池县| 海原县| 宜章县| 盐津县| 桃江县| 巴彦县| 通化市| 米脂县| 电白县| 平原县| 长治县| 邵东县| 宜川县| 无棣县| 娄底市| 洛川县| 远安县| 商丘市| 长岭县| 绍兴县| 上林县| 南投县| 华容县| 明溪县| 龙陵县| 依安县| 贵德县| 玉树县| 耒阳市| 桓仁| 华亭县|