background

Koa official method of use

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 = '

Hello, koa2!

'
; }); // Routing middleware app.use(router.routes()); app.listen(3000); console.log('app started at port 3000... '); Copy the code

Analyze what koa.use () does

Koa is essentially a wrapper around Node’s native HTTP modules and introduces middleware mechanisms, which, as we learned from the example code, are methods by which the entire Web services module can do its job, facilitating development and debugging. In the whole HTTP request, Rquest and response need to go through a series of intermediate processes and then return to the client for use. We assume that there is such an array and a use method inside Koa

let middleWare = []
function use(f){
    middleWare.push(f)
}
Copy the code

After working through a bunch of middleWare, we get this middleWare

let middleWare = [f1,f2,f3,f4,f5,...]
Copy the code

Let me give you an example

async function f1(ctx,next) {
    console.log('Execute to f1')
    next()
}
async function f2(ctx,next) {
    console.log('Execute to f2')
    next()
}
async function f3(ctx,next) {
    console.log('Execute to f3')
    next()
}
async function f4(ctx,next) {
    console.log('Execute to f4')
    next()
}
async function f5(ctx,next) {
    console.log('Execute to f5')
    next()
}
Copy the code

So these are the 5 middleware we’ve been using how do we get these 5 middleware to do this?

Look at the code below

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
// --> execute to f1, f2, F3, F4, f5
Copy the code

Thus, each middleware parameter is a reference function to the next intermediate middleware. So we abstract out a method to generate these next, and then we call the last next to achieve the effect of one call after another

function createNext(middleWare,next){
    return async function(){
        await middleWare(next)
    }
}
Copy the code

We find that the createNext function returns a value that becomes the next middleware parameter, next5 is called by Next4, next4 is called by next3…… By analogy, it is natural to think of the array reduce method, so:

let composeMiddleWare = [f1,f2,f3,f4,f5].reduceRight((pre, cur, i, arr) = > {
    return createNext(cur, pre)
}, () => { })

composeMiddleWare()   // --> execute to f1, f2, F3, F4, f5
Copy the code

Koa source conjecture

From the above analysis, there must be a similar implementation in the KOA source code

let middleWare = []
function use(f){
    middleWare.push(f)
}
function createNext(middleWare,next,ctx){
    return async function(){
        await middleWare(ctx,next)
    }
}
// Combine middleware methods
let composeMiddleWare = (ctx) = >middleWare.reduceRight((pre, cur, i, arr) = > {
    return createNext(cur, pre,ctx)
}, () => { Promise.resolve() })
Copy the code

Analyze the callback function of HTTP module native API [createServer] in Koa that carries request and Response objects when it is executed. Koa encapsulates it and generates a CTX object that mounts part of the attributes of Request and Response. Let’s guess what callback does.

http.createServer((req,res) = >callback(req,res))
function callback(req,res){
    let composeMiddleWare = composeMiddleWare();ComposeMiddleWare above
    let ctx = {req,res}  // If you are interested in the source code, mount all the attributes here
    composeMiddleWare(ctx) // Execute left and right middleware in turn, carrying CTX
}
Copy the code

conclusion

Koa itself is an extremely compact framework, and the introduction of middleware makes it extremely easy to extend, so it is very popular, and there are many big companies that have wrapped their own frameworks based on Koa ideas such as egg.js, etc. I’ll leave it there and write a simple implementation of Koa next time.