本筆記共四篇
Koa源碼閱讀筆記(1) -- co
Koa源碼閱讀筆記(2) -- compose
Koa源碼閱讀筆記(3) -- 服務器の啓動與請求處理
Koa源碼閱讀筆記(4) -- ctx對象javascript
前兩天終於把本身一直想讀的Koa
源代碼讀了一遍。
今天就要來分析Koa的ctx
對象,也就是在寫中間件和處理請求和響應時的那個this對象。
而這個this
對象,也是和Express的重要區別之一。不用再區分req,res
(雖然仍是得知道),一個this
對象就能調用全部方法。
在實際開發中,是很是便利的。前端
在這兒則須要談一談Koa1和Koa2調用this對象的區別。
Koa1在調用時,使用的是this,而Koa2則是ctx。java
// Koa1 app.use(function * (next) { this.body = 'hello world' yield next })
// Koa2 app.use(async (ctx, next) => { ctx.body = 'hello world' await next() })
使用方式,只是把this換成了ctx。
具體爲何出現ctx和next,以前的文章koa-compose的分析有寫。segmentfault
這兒繼續以Koa1爲例,由於看得懂Koa1源代碼的,看Koa2的源碼天然也不難。
首先放上關鍵的源代碼:api
app.callback = function(){ var fn = co.wrap(compose(this.middleware)); var self = this; return function(req, res){ res.statusCode = 404; var ctx = self.createContext(req, res); onFinished(res, ctx.onerror); fn.call(ctx).then(function () { respond.call(ctx); }).catch(ctx.onerror); } };
在上一篇Koa源碼閱讀筆記(3) -- 服務器の啓動與請求處理中,咱們已經分析了fn的做用。
而onFinished則會在請求完成時調用,剩下的則是調用中間件去處理響應。
同時var ctx = self.createContext(req, res);
這一句,不看createContext
這個函數,應該也能猜出它的做用。
以後的fn.call(ctx)
則說明了中間件中this
的來源。
在這兒不得不感嘆一句,JavaScript的this真的是太靈活了,配合閉包,call,apply等,簡直擁有無限魔力。服務器
貼出相關的源代碼:cookie
var response = require('./response'); var context = require('./context'); var request = require('./request'); /** * Initialize a new context. * * @api private */ app.createContext = function(req, res){ var context = Object.create(this.context); var request = context.request = Object.create(this.request); var response = context.response = Object.create(this.response); context.app = request.app = response.app = this; context.req = request.req = response.req = req; context.res = request.res = response.res = res; request.ctx = response.ctx = context; request.response = response; response.request = request; context.onerror = context.onerror.bind(context); context.originalUrl = request.originalUrl = req.url; context.cookies = new Cookies(req, res, { keys: this.keys, secure: request.secure }); context.accept = request.accept = accepts(req); context.state = {}; return context; };
雖然看上去有點繞,可是仔細看看,仍是不難的。
以前說過,Koa的源碼簡潔,一共就4個文件。
除了主要的Application.js
, 剩下就都是與請求和響應相關的了。閉包
這兒,由於每次都要建立並調用ctx
對象。爲了不影響原有的context
,request
,response
對象。
這兒採用了Object.create()
來克隆對象。app
首先就來分析,最開始的context.js。
context的實現很簡單,但有意思的地方在於delegate這個地方。
就以下圖所示:koa
我看了delegate這個源代碼,功能是把context
中相應的方法調用和屬性讀取,委託至某個對象中。
而不用本身一個一個的寫apply
,call
等。
關於request和response,我這兒就不詳細寫了。
在這兒放一張圖足以。
實際上,request和response是經過getter和setter,來實現存取不一樣屬性的功能。
另外,經過剛纔說的delegate方法,則使用ctx對象時,便能自動經過getter和setter獲取想要的內容。
這一篇很簡單,其實也沒啥能夠說的。
由於Koa除了中間件部分看起來複雜,其它地方仍是很簡潔明瞭的。
學習源代碼的過程當中,也發現了不少優雅的寫法,算是開拓了本身的眼界。
從會寫到寫好,看來還要挺長一段時間的。
前端路漫漫,且行且歌。
最後附上本人博客地址和原文連接,但願能與各位多多交流。