前兩篇已經瞭解了yield和generator的相關概念,這篇文章繼續分析Koa的源碼, Koa的用法,這裏就不在列舉了。我以爲Koa主要功能主要是下面幾個方面 1). 提供了中間件機制 2). 封裝了request/response,context對象 3). 使用了yield,提供了便利的流程控制,使異步編程更優雅 4). 便捷的異常處理,使用try catch就能夠捕獲程序中的異常,不須要考慮同步或者異步的問題
import koa from 'koa';
const app = koa();
app.experimental = true;
app.proxy = true;//當 app.proxy 設置爲 true 時,支持 X-Forwarded-Host
//添加一箇中間件
app.use(function*(next) {前端console.log('start'); yield *next; console.log('end'); })app.listen(port);編程
koa會提供不少中間件,好比koa-router,koa-session,koa-bodyparse,koa-server等數組
var app = Application.prototype;
module.exports = Application;session
//函數的入口部分app
function Application() {dom
if (!(this instanceof Application)) return new Application; this.env = process.env.NODE_ENV || 'development'; this.subdomainOffset = 2; this.middleware = []; this.proxy = false; this.context = Object.create(context); this.request = Object.create(request); this.response = Object.create(response); }
listen真正的建立了一個http serverkoa
app.listen = function(){異步
var server = http.createServer(this.callback()); return server.listen.apply(server, arguments); };
中間件use方法, fn必須是一個generator function, 能夠經過'GeneratorFunction' == fn.constructor.name異步編程
app.use = function(fn){ if (!this.experimental) { // 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; };
重要函數來啦,這裏只是分析this.experimental = false的狀況函數
app.callback = function(){ var fn = this.experimental ? compose_es7(this.middleware) : co.wrap(compose(this.middleware)); //co是使用的tj的co模塊,這裏先分析compose的函數用法 //compose 函數是將this.middleware數組的函數進行一個簡單的處理,保證每一個函數都有後一個函數的引用,具體代碼看下面的分析 //co.wrap能夠將一個generation function 進行轉換,使fn可以自動運行 var self = this; if (!this.listeners('error').length) this.on('error', this.onerror); return function(req, res){ res.statusCode = 404; var ctx = self.createContext(req, res); onFinished(res, ctx.onerror); //這裏執行中間件函數,而後將處理的結果都掛在ctx上,最後respond函數輸出到前端,注意catch函數進行錯誤邏輯處理 fn.call(ctx).then(function () { respond.call(ctx); }).catch(ctx.onerror); } };
compose 代碼分析, compse是將middleware裏面的middleware都有下一個函數的引用
function compose(middleware){ return function *(next){ if (!next) next = noop(); var i = middleware.length; while (i--) { next = middleware[i].call(this, next); } return yield *next; } }
至此,koa的源碼已經分析完畢了