Directions for use

  • We know that when we get the instance of KOA, we can use app.use to register a middleware for KOA. And then when we have a pair of servers coming in it triggers our middleware. The middleware has two parameters, CTX, that represent the context of the request, which we will parse in the next article. Next will give the execution authority to the next middleware, in order to execute all the middleware, if not write, then the later middleware will not be executed.
conset Koa = require('koa');
const app = new Koa()
app.use(async (ctx,next) => {
    console.log(ctx, 'Here is the context of the request which includes the reQ, res, etc proxy to the CTX')
    ctx.status = 200
    ctx.body = 'instance'
    await next();
})
Copy the code

Parsing app. Use

  • App. use is used to add middleware functions and can be added in chains. And then when the request comes, call it sequentially. We can then store middleware functions in a queue and each middleware function returns this
const Emitter = require('events');
module.exports = class Koa extends(Emitter) {
    constructor() {
        super(a)this.middleware = [];
    }
    use(fn) {
        this.middleware.push(fn)
        return this; }}Copy the code

Execute middleware functions in order to process HTTP requests

After we’ve saved the middleware functions to queue Middleware, it’s time to parse the requests and execute the middleware functions in order. Remember our callback from the last chapter? Our logic processing is here.

const http = require('http'); const Emitter = require('events'); module.exports = class Koa extends(Emitter) { constructor() { super() this.middleware = []; } use(fn) { this.middleware.push(fn) return this; } listen(... arg) { const server = http.createServer(this.callback); return server.listen(... arg) } callback() { const fn = compose(this.middleware); function handleRequest(req,res) { const ctx = {req,res} return this.handleRequest(ctx, fn) } } handleRequest(ctx, fn) { return fn(ctx).then(console.log('success')).catch(err => {console.log(err)}) } }Copy the code

The compose function is important here, it’s the key logic. Its function is to combine a queue of middleware functions into a single function that can be executed asynchronously and sequentially. Let’s look at the implementation steps

  • 1: Define functions and error-compatible handling.
function compose(middleware) { if (! Array.isArray(middleware)) { throw new TypeError('middleware must be an array! ') } for (const fn of middleware) { if (typeof fn ! == 'function') { throw new TypeError('Middleware must be composed of functions! ') } } return function(context, next) { } }Copy the code
  • 2: Implement a return function to handle middleware. Functionally we want to implement a call to a middleware function and then pass execution to the next middleware function by executing the next parameter.
Return function (context, next) {function dispatch(index) {if (index >= Middleware.length) {console.log(' Finish! ') return } middleware[index](context, dispatch.bind(null, index+=1)) } }Copy the code
  • 3: Handle the async function in middleware. We know that if promise.resolve is a Promise, the state is assumed to be promise.resolve ().then. Here we have async again. We await next(), which returns a promise and therefore iterates through the call. Until all the middleware functions in the queue have been traversed.
Return function (context, next) {function dispatch(index) {if (index >= Middleware.length) {console.log(' Finish! ') // The middleware array completes execution and returns a fullfilled promise. return Promise.resolve() } let fn = middleware[index] try { Promise.resolve(fn(context,dispatch.bind(null, index+=1))) } catch(err) { return Promise.reject(err) } } }Copy the code
  • 4: Handle multiple calls to next in middleware functions. We use a variable pre to store the number of dispatches that were first called, so this time the index must be greater than pre. When some middleware is called multiple times, it is inevitable that the index passed into the Dispatch is less than the PRE.
return function (context, next) { let pre = -1 function dispatch(index) { if (pre >= index) { throw new Error('next() called multiple times') } Pre = index if (index >= middleware.length) {console.log(' Finish! ') // The middleware array completes execution and returns a fullfilled promise. return Promise.resolve() } let current = -1 let fn = middleware[index] try { Promise.resolve(fn(context,dispatch.bind(null, Index +=1)))} catch(err) {return promise.reject (err)}}} For compose, we are ready to implement CTX. As well as supplementing and completing our KOA and testing.Copy the code