您的当前位置:首页正文

深入理解 Koa 框架中间件原理

2020-11-27 来源:汇意旅游网

理解 Koa 的中间件机制(源码分析)

阅读源码,化繁为简,我们看看 koa 的中间件系统是如何实现的。

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);
 }
}

好了,精简结束,一不小心,去枝末节,最后只剩下不到 20 行代码。

这就是框架的核心,简化后的代码非常清晰,有点不可思议,但核心就是这么简单。

我们先分析以上代码做了什么事。

  • 我们定义了一个 middleware 数组来存储中间件。
  • 我们定一个了一个 use 方法来注册一个中间件。其实就是简单的 push 到自身的 mideware 这个数组中。
  • 我们还使用了一个 compose 方法,传入 middleware ,应该是做了一些处理,返回了一个可执行的方法。
  • 你一定对中间的 compose 方法很好奇,初此之外的代码都容易理解,唯独这个 compose 不太知道究竟做了什么。

    其实, compose 就是整个中间件框架的核心。

    compose 之外,代码已经很清楚的定义了

  • 中间件的存储
  • 中间件的注册
  • 而 compose 方法做了最为重要的一件事

  • 中间件的执行
  • 核心源码 compose

    先上码

    function compose(middleware) {
     return function(context, next) {
     // last called middleware #
     let index = -1;
     return dispatch(0);
     function dispatch(i) {
     if (i <= index)
     return Promise.reject(new Error("next() called multiple times"));
     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);
     }
     }
     };
    }
    

    我试图去简化一下这个方法,但方法本身已经足够简洁。

    代码很简洁。

    通过 next()传递 实现中间件调用, 结合 Promise 采用 递归调用 的通知机制。

    看图

    这种形式的控制流让整个 Koa 框架中间件的访问呈现出 自上而下的中间件流 + 自下而上的 response 数据流 的形式。

    Koa 本身做的工作仅仅是定制了中间件的编写规范,而不内置任何中间件。一个 web request 会通过 Koa 的中间件栈,来动态完成 response 的处理。

    koa 在中间件语法上面采用了 async + await 语法来生成 Promise 形式的程序控制流。

    总结

    koa 是非常精简的框架, 其中的精粹思想就是洋葱模型(中间件模型), koa 框架的中间件模型非常好用并且简洁, 但是也有自身的缺陷, 一旦中间件数组过于庞大, 性能会有所下降,我们需要结合自身的情况与业务场景作出最合适的选择.

    显示全文