koa中间件原理

中间件使用

通过 app.use 使用多个中间件:

const app = new Koa();

app.use(async (ctx, next) => {
 //...
 await next();
 //...
});

app.use(async (ctx, next) => {
 //...
 await next();
 //...
});

// 最后一个中间件不需要 next
app.use(async ctx => {
 ctx.body = "Hello World";
});

//...

中间件总体框架

中间件总体流程的核心代码如下:

class Application extends Emitter {
 constructor() {
  super();
  this.middleware = [];
 },

 use(fn) {
  this.middleware.push(fn);
  return this;
 },

 callback() {
  const fn = compose(this.middleware);

  return function(req, res) {
   return fn(ctx);
  };
 },

 listen(...args) {
  const server = http.createServer(this.callback());
  return server.listen(...args);
 }
}

核心 compose 方法实现

function compose(middleware) {
 return function(context, next) {
  // last called middleware #
  let index = -1;
  return dispatch(0);

  function dispatch(i) {
   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);
   }
  }
 };
}