Koa源碼閱讀筆記(2) -- compose

本筆記共四篇
Koa源碼閱讀筆記(1) -- co
Koa源碼閱讀筆記(2) -- compose
Koa源碼閱讀筆記(3) -- 服務器の啓動與請求處理
Koa源碼閱讀筆記(4) -- ctx對象javascript

2016-07-27_19:11:39.jpg

原由

自從寫了個Koa的腳手架koa2-easy,愈發以爲Koa的精妙。
因而抱着知其然也要知其因此然的想法,開始閱讀Koa的源代碼。前端

問題

讀Koa源代碼時,天然是帶着諸多問題的。不管是上一篇所寫的generator函數如何自動執行,仍是對於Koa中間件如何加載,next參數如何來的。都充滿了好奇。
今天寫文章,並非介紹整個koa-compose如何如何(涉及太寬,準備放在下面幾篇統一介紹)。而是從自身需求出發,找到問題的答案。
而問題就是Koa中間件的加載,和next參數的來源java

源碼解讀

初始化與中間件加載

首先的是Koa加載初始化時的函數(刪除部分):git

// Koa類
function Application() {
  this.middleware = [];
}
// Koa原型
var app = Application.prototype;

// Koa中間件加載函數
app.use = function(fn){
  if (!this.experimental) {
    // es7 async functions are not allowed,
    // so we have to make sure that `fn` is a generator function
    assert(fn && 'GeneratorFunction' == fn.constructor.name, 'app.use() requires a generator function');
  }
  this.middleware.push(fn);
  return this;
};

在這兒不難看出,Koa對象內部有個中間件的數組,其中全部中間件都會存在其中。
而在服務器啓動時,則會調用並處理該數組。
源代碼以下:github

var co = require('co');
var compose = require('koa-compose');

var fn = co.wrap(compose(this.middleware))

在fn被處理完後,每當有新請求,便會調用fn,去處理請求。
而在這裏,co.wrap的做用是返回一個Promise函數,用於後續自動執行generator函數。segmentfault

koa-compose

因而不難看出,中間件這兒的重點,是compose函數。
而compose函數的源代碼雖然很簡潔,可是也很燒腦。(對我而言)api

/**
 * Compose `middleware` returning
 * a fully valid middleware comprised
 * of all those which are passed.
 *
 * @param {Array} middleware
 * @return {Function}
 * @api public
 */

// 傳入中間件做爲參數
function compose(middleware){
  return function *(next){
    // next不存在時,調用一個空的generator函數
    if (!next) next = noop();

    var i = middleware.length;
    // 倒序處理中間件,給每一箇中間件傳入next參數
    // 而next則是下一個中間件
    while (i--) {
      next = middleware[i].call(this, next);
    }

    return yield *next;
  }
}

function *noop(){}

在這裏,得提一提Koa中間件的調用方式。數組

app.use(function * (next) {
  this.set('Koa', 'Example');
  yield next;
})
app.use(function * (next) {
  this.body = 'Hello World'
})

在中間件中的next,則是在koa-compose中傳入的。
而這兒, yield nextyield *next也是有區別的。
yield next, next 會做爲next()的value返回。
yield *next則是在generator函數內執行這個generator函數。服務器

結語

這兩天一直在讀Koa的源代碼,細細看來不是很難,可是被做者的奇思妙想給打動了。
接下來會繼續寫一些閱讀筆記,由於看Koa的源代碼確實是獲益匪淺。app


前端路漫漫,且行且歌

最後附上本人博客地址和原文連接,但願能與各位多多交流。

Lxxyx的前端樂園
原文連接:Koa源碼閱讀筆記(2) -- compose

相關文章
相關標籤/搜索