告別回調噩夢,從這裏開始
express
請看下面來自官網的代碼和執行順序:koa
以上代碼的實現若是用回調函數來實現,無疑是一場噩夢,而KOA卻以十分優雅的方式實現了以下圖洋蔥圖通常的回調:函數
核心是利用ES6的新特性:generatorcode
具體實現是利用KOA的兩個NIUBI轟轟的模塊:compose和CO中間件
compose模塊,用於將全部generator中間件串聯起來,基本上就是將後一個generator賦給前一個generator的next參數。也就是在yield後面調用下一個generate函數。
大體原理:對象
// 中間件 a function* a(next) { yield 1; // 執行下一個中間件 yield* next; yield '繼續執行A中間件'; } // 中間件 b function* b(next) { yield 2; yield 3; } var next = function* (){}; var i = [a, b].length; // 經過next首尾相連 while(i--) { next = [a, b][i].call(null, next); } // 包裹第一個middleware function* start(ne) { return yield* ne; } // 輸出 console.log(start(next).next()); console.log(start(next).next()); console.log(start(next).next()); console.log(start(next).next()); 輸出結果: ➜ a-lab ./a { value: 1, done: false } { value: 2, done: false } { value: 3, done: false } { value: '繼續執行A中間件', done: false }
這裏能夠看出來:compose取中間件是作i-循環的,可是因爲一開始是吧中間件推入棧中,順序爲FILO,全部順序是沒問題的。blog
可是:那個負責把全部中間件串起來的next其實自己也是一個generator,可是,若是在Generater函數內部,調用另外一個Generator函數,默認狀況下是沒有效果的。遞歸
因此這時候就輪到咱們的CO模塊出場啦路由
CO模塊:CO模塊便經過遞歸使得嵌套好的generate依次自動執行(包裝爲Promise對象)
大體源碼實現generator
function run(gen){ var g; if (typeof gen.next === 'function') { g = gen; } else { g = gen(); } function next(){ var tmp = g.next(); //若是tmp.done爲true,那麼證實generator執行結束,返回。if (tmp.done) { return; } elseif (typeof g.next === 'function') { run(tmp.value); next(); } } next(); }