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

 更新时间£º2018年10月18日 08:40:00   作者£ºWEBOOK   我要评论

koa是目前node里最流行的web框架¡£这篇文章主要介绍了理解 Koa 框架中间件原理£¬小编觉得挺不错的£¬现在分享给大家£¬也给大家做个参考¡£一起跟随小编过来看看吧

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

在 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 模块£¬ http 的 createServer 方法创建了一个 http.Server 的实例¡£
  • server 监听 3000 端口¡£
  • 我们传入到 createServer 里的函数?#23548;?#26159;监听 request 事件的回调£¬每当请求进来£¬监听函数就会执行¡£
  • request 事件的监听函数£¬其函数接受两个参数£¬分别是 req 和 res ¡£其中 req 是一个可读流£¬ res 是一个可写流¡£我们通过 req 获取 http 请求的所?#34892;?#24687;£¬同时将数据写入到 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);

中间件概念在编程中使用广泛, 不管是前端还是后端, 在?#23548;?#32534;程中或者框架设计都有使用到这?#36136;?#29992;的模型¡£

基本上£¬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 行代码¡£

这就是框架的核心£¬简化后的代码非常清晰£¬有点不可?#23478;?但核心就是这么简单¡£

我们先分析以上代码做了什?#35789;¡?/p>

  • 我们定义了一个 middleware 数组来存储中间件¡£
  • 我们定一个了一个 use 方法来注册一个中间件¡£其实就是简单的 push 到自身的 mideware 这个数组中¡£
  • 我们还使用了一个 compose 方法£¬传入 middleware £¬应该是做了一些处理£¬返回了一个可执行的方法¡£

你一定对中间的 compose 方法很好奇£¬初此之外的代码都容易理解£¬唯独这个 compose 不太知道究竟做了什?#30784;?/p>

其实£¬ compose 就是整个中间件框架的核心¡£

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

  • 中间件的存储
  • 中间件的注册

而 compose 方法做了最为重要的一件事

  • 中间件的执行

核心源码 compose

先?#19979;?/p>

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 采用 递归调用 的通知机制¡£

看图

这?#20013;?#24335;?#30446;?#21046;流让整个 Koa 框架中间件的访问呈现出 自上而下的中间件流 + 自下而上的 response 数据流 的形式¡£

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

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

总结

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

以上就是本文的全部内容£¬希望对大家的学习有所帮助£¬也希望大家多多支持脚本之家¡£

相关文章

  • 详解nodejs操作mongodb数据库封装DB类

    详解nodejs操作mongodb数据库封装DB类

    这篇文章主要介绍了详解nodejs操作mongodb数据库封装DB类,小编觉得挺不错的£¬现在分享给大家£¬也给大家做个参考¡£一起跟随小编过来看看吧
    2017-04-04
  • nodejs后台集成ueditor富文本编辑器的实例

    nodejs后台集成ueditor富文本编辑器的实例

    本篇文章主要介绍了nodejs后台集成ueditor富文本编辑器的实例£¬具有一定的参考价值£¬?#34892;?#36259;?#30446;?#20197;了解一下
    2017-07-07
  • 最新评论

    常用在线小工具

    ÁÉÄþ35Ñ¡7¿ª½±½á¹û