Koa

koa

一、洋葱模型

二、洋葱模型原理

洋葱模型可以理解成函数嵌套调用

koa 中,中间件被 next() 方法分成了两部分。next() 方法上面部分会先执行,下面部分会在后续中间件执行全部结束之后再执行。

原理模拟:

function A(next) {
  console.log("A start");
  typeof next === "function" && next();
  console.log("A end");
}

function B(next) {
  console.log("B start");
  typeof next === "function" && next();
  console.log("B end");
}

function C(next) {
  console.log("C start");
  typeof next === "function" && next();
  console.log("C end");
}

function D() {
  console.log("D start");
  console.log("D end");
}

A(B.bind(null, C.bind(null, D)));

运行结果:

A start
B start
C start
D start
D end
C end
B end
A end

compose函数模拟

koa是通过koa-compose库进行中间件调用的,我们可以通过写一个简版compose函数模拟下

方式1:Array.prototype.reduceRight

const mws = [A, B, C, D];
function compose(allMW) {
  return allMW.reduceRight((pre, cur) => {
    return cur.bind(null, pre);
  });
}

let mwFn = compose(mws);
mwFn();

方式2:柯里化方式(递归)

const mws = [A, B, C, D];
function compose(allMW) {
  function dispatch(i) {
    let middleware = allMW[i];
    if (!middleware) return;
    return middleware.bind(null, dispatch(i + 1));
  }

  return dispatch(0);
}

let mwFn = compose(mws);
mwFn();

三、简版koa

class Koa {
  constructor() {
    this.middlewareList = [];
    this.context = {
      request: null,
      response: null,
    };
  }

  use(middleware) {
    this.middlewareList.push(middleware);
  }

  compose(middlewareList) {
    return function (ctx) {
      function dispatch(index) {
        const middleware = middlewareList[index];
        if (!middleware) return;
        return middleware(ctx, dispatch.bind(null, index + 1));
      }

      return dispatch(0);
    };
  }
}

测试代码:

const app = new Koa();

app.use((ctx, next) => {
  console.log("A start");
  next();
  console.log("A end");
});

app.use((ctx, next) => {
  console.log("B start");
  next();
  console.log("B end");
});

app.use((ctx, next) => {
  console.log("C start");
  next();
  console.log("C end");
});

app.use((ctx, next) => {
  console.log("D start");
  next();
  console.log("D end");
});

const run = app.compose(app.middlewareList);
run();

运行结果:

A start
B start
C start
D start
D end
C end
B end
A end

koa-compose源码入口

参考:

Last updated