Koa中介軟體原理
阿新 • • 發佈:2019-12-31
背景
Koa官方使用方法
const Koa = require('koa');
var Router = require('koa-router');
var router = new Router();
const app = new Koa();
app.use(async (ctx,next) => {
await next();
ctx.response.type = 'text/html';
ctx.response.body = '<h1>Hello,koa2!</h1>';
});
//路由中介軟體
app.use(router.routes());
app.listen(3000 );
console.log('app started at port 3000...');
複製程式碼
分析Koa.use()做了什麼
Koa本質上是對node原生http模組的封裝,並且引入了中介軟體機制,通過示例程式碼我們也知道,中介軟體就是一個個方法,通過這些方法使得整個web服務模組可以各司其職,有助於開發與除錯。在整個http請求中,rquest與response需要經過一系列的中間過程處理然後返回給客戶端使用。我們猜想在Koa的內部有這樣的一個陣列和一個use方法
let middleWare = []
function use(f){
middleWare.push(f)
}
複製程式碼
在使用過一系列中介軟體之後,我們會得到這樣一個middleWare
let middleWare = [f1,f2,f3,f4,f5,...]
複製程式碼
舉個列子說明
async function f1(ctx,next) {
console.log('執行到f1')
next()
}
async function f2(ctx,next) {
console.log('執行到f2')
next()
}
async function f3(ctx,next) {
console.log('執行到f3')
next()
}
async function f4(ctx,next) {
console.log('執行到f4')
next()
}
async function f5(ctx,next) {
console.log('執行到f5')
next()
}
複製程式碼
以上是我們已經使用的5箇中介軟體 我們怎麼做到讓這5箇中介軟體以此執行呢?
看下面的程式碼
let next1 = async function (ctx) {
await f1(ctx,next2)
}
let next2 = async function (ctx) {
await f2(ctx,next3)
}
let next3 = async function (ctx) {
await f3(ctx,next4)
}
let next4 = async function (ctx) {
await f4(ctx,next5)
}
let next5 = async function (ctx) {
await f5()
}
next1(ctx) // next() === f1(f2(f3(f4(f5)))) ---> true
// ---> 執行到f1,執行到f2,執行到f3,執行到f4,執行到f5
複製程式碼
由此看出,每個中介軟體的引數,是對於下一個中間中介軟體的引用函式。於是我們抽象一個方法出來來生成這些next,然後最後呼叫最後一個next就可以達到依次呼叫的效果
function createNext(middleWare,next){
return async function(){
await middleWare(next)
}
}
複製程式碼
我們發現,createNext函式返回值又會成為下一個中介軟體的引數,next5被next4呼叫,next4又被next3呼叫......依次類推,很自然的就想到了陣列的reduce方法 因此:
let composeMiddleWare = [f1,f5].reduceRight((pre,cur,i,arr) => {
return createNext(cur,pre)
},() => { })
composeMiddleWare() // ---> 執行到f1,執行到f2,執行到f3,執行到f4,執行到f5
複製程式碼
Koa原始碼猜想
從上面的分析可得,koa原始碼中肯定有類似的實現
let middleWare = []
function use(f){
middleWare.push(f)
}
function createNext(middleWare,next,ctx){
return async function(){
await middleWare(ctx,next)
}
}
//組閤中介軟體方法
let composeMiddleWare = (ctx) =>middleWare.reduceRight((pre,pre,ctx)
},() => { Promise.resolve() })
複製程式碼
分析Koa中http模組原生api【createServer】的回撥函式callback執行的時候攜帶了request與response物件,koa對其進行了封裝生成了一個ctx物件,掛載了request,response上的部分屬性,我們來猜猜callback裡面做了什麼?
http.createServer((req,res)=>callback(req,res))
function callback(req,res){
let composeMiddleWare = composeMiddleWare();//上面的composeMiddleWare
let ctx = {req,res} //有興趣去看看原始碼,這裡掛載全部屬性
composeMiddleWare(ctx) //依次執行左右的中介軟體,並攜帶ctx
}
複製程式碼
結語
Koa本身就是一個及其精簡的框架,中介軟體的引入使它極其容易擴充套件,因此很受歡迎,也有很多大廠基於KOa的思想封裝了自己的框架比如egg.js等等。先分析到這兒,下次寫一篇Koa的簡單實現。