1. 程式人生 > 程式設計 >Koa中介軟體原理

Koa中介軟體原理

背景

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的簡單實現。