本文將會你們來看下koa
的源碼,固然本文須要你們瞭解koa
的中間件機制,若是你們以前沒有了解過其實現原理,能夠關注下這篇文章。koa
的源碼很是的精簡,與express
不一樣,koa
只是爲開發者搭起了一個架子,沒有任何的功能,包括路由,所有由中間件實現;下面就來看下koa
的實現:node
建立應用時,通常都會利用app.listen
指定一個端口號,這個方法的本質就是http.createServer
:git
listen() { debug('listen'); const server = http.createServer(this.callback()); return server.listen.apply(server, arguments); }
最爲關鍵的就是這個callback
的實現:github
callback() { const fn = compose(this.middleware); if (!this.listeners('error').length) this.on('error', this.onerror); const handleRequest = (req, res) => { res.statusCode = 404; const ctx = this.createContext(req, res); const onerror = err => ctx.onerror(err); const handleResponse = () => respond(ctx); onFinished(res, onerror); return fn(ctx).then(handleResponse).catch(onerror); }; return handleRequest; }
須要注意下面幾點:express
onFinished(res, onerror)
,應對的是返回的body
爲Stream
的狀況,爲其添加一個finished
事件。npm
respond()
根據ctx
的status,body,method
來決定如何響應此次請求:api
status
爲204,304
,不須要有響應體,res.end()
就好cookie
method
爲HEAD
,HEAD
的意義是不請求資源內容可是須要了解資源狀況,因此只須要請求頭,指定了資源length
後res.end()
就好app
加入body
爲空,則body
爲statuses
包中status
對應的文字描述,如404 => Not Found
koa
koa
將request
對象response
封裝成了一個對象,提供了一些別名,具體能夠參見context對象,例如:當訪問ctx.url
實則是訪問的ctx.request.url
。具體的實現利用了tj寫的delegates
這個npm
包來對context
對象添加屬性,koa
中利用了其中三個api
:socket
method
:添加方法引用
getter
:利用__defineGetter__
,添加getter
屬性
access
:添加getter
與setter
對於context
建立的代碼:
createContext(req, res) { const context = Object.create(this.context); const request = context.request = Object.create(this.request); const 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.originalUrl = request.originalUrl = req.url; context.cookies = new Cookies(req, res, { keys: this.keys, secure: request.secure }); request.ip = request.ips[0] || req.socket.remoteAddress || ''; context.accept = request.accept = accepts(req); context.state = {}; return context; }
函數的參數req, res
爲node自己的對象,request
和response
分別是對於req
和res
的封裝,讀取ctx.url
的過程以下:
context
就是一個頂層對象,koa
中,全部的屬性和操做基本會基於這個對象,這個對象的組成以下圖:
我的感受koa
就像是一個架子,提供了基礎的方法和屬性,如ctx.redirect
等,具體的功能主要利用中間件來實現,與express
相比,koa
去除內置路由,views
等,變得更加的輕量;固然我認爲更加劇要的是避免了層層回調的出現。以上內容若有出錯,歡迎你們指出。