ES6異步編程

阮一峰網絡日志:http://www.ruanyifeng.com/blog/2015/04/generator.html


什么是異步

不連續的執行即為異步。

簡單的說,異步就是一個任務分成兩段,先執行第一段,然后轉而執行其他任務,等做好了準備,再回過頭執行第二段。   
  比如,有一個任務是讀取文件進行處理,異步的執行過程就是下面這樣:
異步示例.png
同步:連續的執行即為同步。一個任務開始執行到結束,中間不能插入其他任務。
同步示例.png

ES6之前的異步編程方法

1. 回調函數

  • 回調函數callback
    把任務的第二段寫在一個函數里,等任務重新執行時就重新調用該函數。
    fs.readFile('/etc/passwd', function (err, data) {
      if (err) throw err;
      console.log(data);
    });
   上面代碼中,readFile 函數的第二個參數就是回調函數,即任務的第二段。等操作系統返回文件“/etc/passwd ”后,回調函數才會執行。
   Node.js 約定,回調函數的第一個參數,必須是錯誤對象err(如果沒有錯誤,該參數就是 null)。
   原因是執行分成兩段,在這兩段之間拋出的錯誤,程序無法捕捉,只能當作參數,傳入第二段
    fs.readFile(fileA, function (err, data) {
      fs.readFile(fileB, function (err, data) {
        // ...
      });
    });
   回調函數嵌套,可能導致代碼是橫向發展的,這樣子的代碼就會發生混亂很難管理。
  • Promise : 回調函數的改進
  1、Promise 允許將回調函數的橫向加載,改成縱向加載.
  2、Promise 提供 then 方法加載回調函數,catch方法捕捉執行過程中拋出的錯誤
  3、使用then方法以后,異步任務的兩段執行看得更清楚
    var readFile = require('fs-readfile-promise');
    readFile(fileA)
    .then(function(data){
      console.log(data.toString());
    })
    .then(function(){
      return readFile(fileB);
    })
    .then(function(data){
      console.log(data.toString());
    })
    .catch(function(err) {
      console.log(err);
    });
   Promise會導致代碼冗余,過多的then會導致語義不清晰

2. 協程 https://en.wikipedia.org/wiki/Coroutine

協程,即多個線程完成協作,完成異步任務。協程有點像函數,又有點線程,其運行流程如下:
   第一步,協程A開始執行。
   第二步,協程A執行到一半,進入暫停,執行權轉移到協程B。
   第三步,(一段時間后)協程B交還執行權。
   第四步,協程A恢復執行。
上面流程的協程A,就是異步任務,因為它分成兩段(或多段)執行
   function asnycJob() {
     // ...其他代碼
     var f = yield readFile(fileA);
     // ...其他代碼
   }
yield命令:表示執行暫停,執行權交給其他協程,是異步兩個階段的分界線。

上面代碼的函數 asyncJob 是一個協程,它的奧妙就在其中的 yield 命令。它表示執行到此處,執行權將交給其他協程。也就是說,yield命令是異步兩個階段的分界線。

2. Gennerator函數

Generator 函數可以暫停執行和恢復執行,這是它能封裝異步任務的根本原因

Generator函數是協程在 ES6 的實現,最大特點就是可以交出函數的執行權(即暫停執行)

  function* gen(x){
      var y = yield x + 2;
      return y;
    }
上面代碼就是一個 Generator 函數。它不同于普通函數,是可以暫停執行的,所以函數名之前要加星號,以示區別
整個 Generator 函數就是一個封裝的異步任務,或者說是異步任務的容器。異步操作需要暫停的地方,都用 yield 語句注明

Generator 函數的執行方法如下:

    var g = gen(1);
    g.next() // { value: 3, done: false }
    g.next() // { value: undefined, done: true }

上面代碼中,調用 Generator 函數,會返回一個內部指針(即遍歷器 )g 。這是 Generator 函數不同于普通函數的另一個地方,即執行它不會返回結果,返回的是指針對象。調用指針 g 的 next 方法,會移動內部指針(即執行異步任務的第一段),指向第一個遇到的 yield 語句,上例是執行到 x + 2 為止。

換言之,next 方法的作用是分階段執行 Generator 函數。每次調用 next 方法,會返回一個對象,表示當前階段的信息( value 屬性和 done 屬性)。value 屬性是 yield 語句后面表達式的值,表示當前階段的值;done 屬性是一個布爾值,表示 Generator 函數是否執行完畢,即是否還有下一個階段。

Generator 函數的數據交換和錯誤處理
Generator 函數還有兩個特性,使它可以作為異步編程的完整解決方案:函數體內外的數據交換和錯誤處理機制

next方法返回值的value 屬性,是 Generator 函數向外輸出數據;next 方法還可以接受參數,這是向 Generator 函數體內輸入數據
    function* gen(x){
      var y = yield x + 2;
      return y;
    }
    var g = gen(1);
    g.next() // { value: 3, done: false }
    g.next(2) // { value: 2, done: true }

上面代碼中,第一個 next 方法的 value 屬性,返回表達式 x + 2 的值(3)。第二個 next 方法帶有參數2,這個參數可以傳入 Generator 函數,作為上個階段異步任務的返回結果,被函數體內的變量 y 接收。因此,這一步的 value 屬性,返回的就是2(變量 y 的值)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,182評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,489評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,290評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,776評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,510評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,866評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,860評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,036評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,585評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,331評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,536評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,058評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,754評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,154評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,469評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,273評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,505評論 2 379

推薦閱讀更多精彩內容