看Koa框架源码,搞懂compose核心

栏目: Node.js · 发布时间: 5年前

内容简介:本文分析了Koa框架的核心源码,看懂了compose方法,也就看懂了 Koa。Node 主要用在开发 Web 应用,koa 是目前 node 里最流行的 web 框架。在 Node 开启一个 http 服务简直易如反掌,下面是官网 demo。

本文分析了Koa框架的核心源码,看懂了compose方法,也就看懂了 Koa。

Node 主要用在开发 Web 应用,koa 是目前 node 里最流行的 web 框架。

一个简单的 http 服务

在 Node 开启一个 http 服务简直易如反掌,下面是官网 demo。

const http = require("http");

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader("Content-Type", "text/plain");
  res.end("Hello World\n");
});

const hostname = "127.0.0.1";
const port = 3000;
server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});
复制代码
  • 引入 http 模块, httpcreateServer 方法创建了一个 http.Server 的实例。
  • server 监听 3000 端口。
  • 我们传入到 createServer 里的函数实际是监听 request 事件的回调,每当请求进来,监听函数就会执行。
  • request 事件的监听函数,其函数接受两个参数,分别是 reqres 。其中 req 是一个可读流,res 是一个可写流。我们通过 req 获取 http 请求的所有信息,同时将数据写入到 res 来对该请求作出响应。

Koa 应用

Koa 如何创建一个 server, 直接上个官网的例子

const Koa = require("koa");
const app = new Koa();

// x-response-time
app.use(async (ctx, next) => {
  const start = Date.now();
  await next();
  const ms = Date.now() - start;
  ctx.set("X-Response-Time", `${ms}ms`);
});

// logger
app.use(async (ctx, next) => {
  const start = Date.now();
  await next();
  const ms = Date.now() - start;
  console.log(`${ctx.method} ${ctx.url} - ${ms}`);
});

// response
app.use(async (ctx) => {
  ctx.body = "Hello World";
});

app.listen(3000);
复制代码

中间件概念在编程中使用广泛, 不管是前端还是后端, 在实际编程或者框架设计中都有使用到这种实用的模型。

基本上,Koa 所有的功能都是通过中间件实现的。

每个中间件默认接受两个参数,第一个参数是 Context 对象,第二个参数是 next 函数。只要调用 next 函数,就可以把执行权转交给下一个中间件。

如果中间件内部没有调用 next 函数,那么执行权就不会传递下去。

多个中间件会形成一个栈结构(middle stack),以“先进后出”(first-in-last-out)的顺序执行。整个过程就像,先是入栈,然后出栈的操作。

上面代码的执行顺序是:

请求 -> x-response-time 中间件 -> logger 中间件 -> response 中间件 -> logger 中间件 -> response-time 中间件 -> 响应

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,顾名思义,相当于把所有注册的中间件组合,它规定了中间件的执行顺序,返回一个“大”中间件,这个大中间件,就在 node 的 http 服务 onRequest 事件的时候执行。

核心 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);
      }
    }
  };
}
复制代码

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

通过 compose 方法,可以看出 next 指的就是下一个中间件,也就是我们所编写的中间件方法的第二个参数,Koa 通过 next()传递 实现中间件调用,结合 Promise 采用 递归调用 的通知机制,最终完成整个中间件栈的执行。

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

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

看懂了 compose 方法,也就看懂了 Koa,你大概不愿相信如此简单怎么足以称为框架,但情况就是这样。

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

总结

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


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Creative Curve

The Creative Curve

Allen Gannett / Knopf Doubleday Publishing Group / 2018-6-12

Big data entrepreneur Allen Gannett overturns the mythology around creative genius, and reveals the science and secrets behind achieving breakout commercial success in any field. We have been s......一起来看看 《The Creative Curve》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具