koa-中間件流程控制

koa中間件執行流程

koa中間件的的執行順序是洋蔥模型,外層逐步向內,執行到最中間再逐步向外擴展,實現這個順序的模型須要依賴於generator函數,它能夠暫停執行將控制權交出,等到執行next再獲得執行權繼續執行,咱們須要作的就是將generator串聯起來,將後面的generator函數跟在上一層函數的yield語句以後,能夠看做後面的函數是next的參數,這樣咱們就造成了一個串聯,它的執行順序就是咱們前面所提到的洋蔥模型。node

koa-compose

在koa中,實現上面所說的串聯函數就是利用了compose,下面是compose的大概實現(在koa中叫koa-compose):es6

function compose (middlewares) {
    return function (next) {
        var i = middlewears.length;
        var next = function* () {}();
        while (i--) {
            next = middlewares[i].call(this, next); 
        
            <!--這一點不太好理解:首先這是個遞減的過程,咱們會先取到最後的一個函數
            而後,next函數實際上是起到一箇中介的做用,將next傳入後又從新更新了next
            也就是在下一此的運行中next函數是帶有剛剛那個最內層的函數的(最後一個)
            因而再進行操做,是一個遞歸傳入的過程,能夠看這篇文章:https://cnodejs.org/topic/5723360e35af8a704195f5d5
            -->
        }
        return next;
    }
}

在koa的源碼中有這樣的代碼:數組

var fn = this.experimntal
    ? compose_es7(this.middleware)
    : co.wrap(compose(this.middleware));

咱們添加中間件的時候使用app.use方法,其實這個方法只是把中間件push到一個數組,很明顯,全部的中間件在數組中,那麼它們之間是沒有聯繫的,因此咱們會看到上面的代碼,將全部的中間件都傳入了咱們所說的compose中。通過compose轉換的代碼是下面這樣promise

//達到了洋蔥模型的效果
function *() {
    yield *g1(g2(g3()))
}

co模塊

上面咱們看到經過使用koa-compose將中間件聯繫在一塊兒(串聯),但是在koa中須要調用next()方法才能夠驅動函數向下執行。這時候就須要用到co模塊。它能夠幫咱們自動管理generator的next,並根據調用返回value作出不一樣的響應;若是遇到另一個generator,co會繼續調用本身,這就是咱們爲何須要co。
簡單實現原理:app

function run (gen) {
    var g;
    if (typeof gen.next === 'function') {
        g = gen;
    } else {
        g = gen();
    }
    function next () {
        var tmp = g.next();
        if (tmp.done) {
            return;
        } else if (typeof g.next === 'function') {
            run(tmp.value);  // 將下一步傳入run函數當中
            next();
        }
    } 
    next();
}

經過遞歸的方式(判斷是否執行結束),來驅動generator的執行。koa

關於co模塊的補充(es6)
  • co會返回一個Promise對象,所以咱們可使用then方法添加回調函數
  • co真正的源碼作了什麼
    • 檢查當前代碼是否爲Generator函數的最後一步,若是是就返回
    • 確保每一步返回的結果都是promise對象
    • 使用then方法爲返回值加上回調函數,而後經過onFulfilled函數再次調用next函數
    • 在參數不符合要求的狀況下將promise狀態改成Rejected從而終止模塊。

ps:理解有限,若是有誤請指出!

相關文章
相關標籤/搜索