Koa
是由Express
原班人馬打造,可是相較於Express
的大而全,Koa
是小而精的。Koa
沒有綁定不少的框架以及插件,更容易讓咱們進行擴展,包括如今較爲流行的EggJS
and ThinkJS
都是基於Koa
開發的。Koa
避免了Express中間件基於callback形式的調用,它使用了咱們JS新版本特性,Koa1
中間件藉助於咱們的co
and generator
特性,Koa2
藉助了Promise
and async await
特性,更好的進行流程控制以及catch咱們的錯誤。Koa
提供了Context
對象,其實是對咱們node中request
and response
對象的封裝,咱們不須要不少的手動處理咱們的request
and response
對象。Context
是貫穿咱們整個請求的過程,咱們能夠中間件須要傳遞參數掛在到Context
對象上。(栗子:咱們能夠將用戶信息掛在它上面,經過ctx.state.user
進行操做。)Koa
的中間件執行機制:洋蔥圈模型
。它不是按順序執行的,多箇中間件會造成一個先進後出
的棧結構,當前中間件掌握下一個中間件的執行權,對於流程控制以及後置處理邏輯的實現很是有效。Koa1
藉助co
and generator
管理咱們的中間件,Koa2
藉助async await
(async函數返回的是Promise
對象)管理咱們的中間件。context
對象獲取:Koa1
經過this
對象(this.req
,this.res
)獲取,Koa2
經過ctx
參數(ctx.req
, ctx.res
)獲取。Koa2
的輪子多且成熟,生態比Koa1
豐富。listen
方法建立了咱們的http服務器,端口是
3000
。而且經過
use
方法傳入了三個
koa
中間件, 而且
console
出咱們的執行結果。
listen
方法提及lib
文件,咱們在栗子中require('koa')
其實是引入的lib/application.js
裏面的Application
類。下面咱們來分析一下咱們的listen
方法的實現,首先咱們看一下這個Application
類裏面到底有些什麼:Application
類下有咱們的listen
方法,方法以下:listen
方法裏面的
this.callback()
實際上也返回是一個函數,這個函數接收req、res兩個入參。
this.callback()
裏的callback方法是啥樣的:這個方法接收兩個參數: 一個是咱們的compose的返回結果fn、另外一個是咱們的ctx對象,這個方法主要是對咱們請求的處理以及錯誤的統一捕獲以及處理。javascript
Koa的中間件執行機制有個形象的稱呼-洋蔥圈模型。咱們先執行栗子代碼,看看輸出的結果究竟是什麼? 前端
再回到上文提到的callback函數,咱們的中間件執行機制的核心就是compose(this.middleware),下面咱們來分析一下compose函數的源碼: java
Promise.reslove()
。// Promise.reslove返回一個fulfillled狀態的promise對象
// 能夠當作new Promise()的快捷方式
Promise.reslove(fn(context, dispatch.bind(null, i+1)));
// 其實是等於
new Promise((relove, reject) => {
reslove(fn(context, dispatch.bind(null, i+1)));
})
複製代碼
Promise.reslove(fn(context, dispatch.bind(null, i + 1)))
, 這個fn(context, dispatch.bind(null, i + 1))
也就是執行咱們經過app.use
加入的middleware函數,middleware函數統一接收兩個參數一個是context,一個是next:下一個middleware函數,這樣能夠看出來若是咱們koa中某個中間件沒有執行next方法,那麼以後加入的中間件是不會執行的。這也就造成了咱們的洋蔥圈模型
。// 核心方法:遞歸調用咱們middlewares, 基於Promise進行異步流程控制;
// Promise.resolve()返回的是一個thenable對象;
// 因此咱們koa2中中間件都基於async函數,await等待下箇中間件方法的執行;
return function (context, next) {
// last called middleware #
let index = -1
return dispatch(0)
function dispatch (i) {
if (i <= index) return Promise.reject(new Error('next() called multiple times'))
index = i
let fn = middleware[i]
if (i === middleware.length) fn = next
if (!fn) return Promise.resolve()
try {
return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
} catch (err) {
return Promise.reject(err)
}
}
}
複製代碼
先進後出
的棧結構,當前中間件掌握下一個中間件的執行權。Koa1
藉助co
and generator
管理咱們的中間件,Koa2
藉助async await
(async函數返回的是Promise
對象)管理咱們的中間件。這是一個全棧開發實戰實例:koa2-mysql-sequelize-JWT(供參考交流,一塊兒學習)。node
這是一個我的博客(前端修煉指南):front-end-Web-developer-interviewmysql