Koajs中间件之定义(二)

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

内容简介:第一篇文章中我们讲过,“在Koa中,中间件是指连贯整个 Koa 应用程序,并共享资源的独立插件”,注意两个词,“连贯”与“共享资源”,与上面的代码一一对应,“连贯”对应“next”,“共享资源对应context”。Koa 中通过 next 贯穿整个应用程序,下面分析一下 next 中做了什么。Koa 类中的构造函数中初始化了一堆数据,其中两个重要的,一个是“middleware”,另一个是“context”。(非关键代码使用…省略)

第一篇文章中我们讲过,“在Koa中,中间件是指连贯整个 Koa 应用程序,并共享资源的独立插件”,注意两个词,“连贯”与“共享资源”,与上面的代码一一对应,“连贯”对应“next”,“共享资源对应context”。

Koa 中通过 next 贯穿整个应用程序,下面分析一下 next 中做了什么。

中间件集合

Koa 类中的构造函数中初始化了一堆数据,其中两个重要的,一个是“middleware”,另一个是“context”。(非关键代码使用…省略)

constructor() {
    ...
    this.middleware = [];
    this.context = Object.create(context);
    ...
  }

所有的中间件在一个数组存放,当我们调用“app.use”方法的时候会往数组中加入我们自定义的中间价

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

最后通过“koa-compose”来统一触发中间件队列

callback() {
    const fn = compose(this.middleware);
    ...
    return (req, res) => {
      ...
      fn(ctx).then(() => respond(ctx)).catch(ctx.onerror);
    };
}

koa-compose

koa-compose 源码只有短短几十行,关键代码不到10行,直接贴上源码

function compose (middleware) {
  if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
  for (const fn of middleware) {
    if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')
  }

  /**
   * @param {Object} context
   * @return {Promise}
   * @api public
   */

  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, function next () {
          return dispatch(i + 1)
        }))
      } catch (err) {
        return Promise.reject(err)
      }
    }
  }
}

如果我们需要使用 Koa 的洋葱模型可以直接调用 koa-componse 来达到目的

const koaCompose = require('koa-compose');

const middleware1 = (ctx, next) => {
    console.log('middleware1 >>>>>');
    next();
    console.log('middleware1 <<<<<');
}
const middleware2 = (ctx, next) => {
    console.log('middleware2 >>>>>');
    next();
    console.log('middleware2 <<<<<');
}

const middleware3 = (ctx, next) => {
    console.log('middleware3 >>>>>');
    console.warn(ctx);
    next();
    console.log('middleware3 <<<<<');
}

const fn = koaCompose([middleware1, middleware2, middleware3]);

fn({ a: 'a' }, (ctx) => {
    console.warn(ctx);
    console.warn('The last next use do =======<');
    return ctx;
}).then((ctx) => {
    console.warn(ctx);
    console.warn('end =====<');
});

输出:

middleware1 >>>>>
middleware2 >>>>>
middleware3 >>>>>
{ a: 'a' }
{ a: 'a' }
The last next use do =======<
middleware3 <<<<<
middleware2 <<<<<
middleware1 <<<<<
undefined
end =====<

精简 koa-componse

为了更好的分析代码,去除 koa-componse 代码中的各种非关键判断及异步处理逻辑后,代码如下

const compose = function (middlewares) {
    // 返回一个函数,提供两个参数,一个是传入的上下文,另一个是所有中间件执行完毕后回调
    return function(context, last) {
        let idx = -1;   // 初始定义当前执行中间件下标未-1,即表示当前未执行任何中间件
        
        
        return dispatch(0); // 手动触发第1个中间件

        function dispatch(i) {
            idx = i;    // 设置当前执行中间件下标
            let fn = middlewares[i] || last;    
            try {
                // 执行当前中间件的时候,给当前中间件参数中的next参数赋值为一个函数,在这个函数中执行下一个中间件
                if (fn) fn(context, function() {
                    dispatch(i + 1);    // 触发下一个中间价,并且将中间件执行下标+1
                })
            } catch (err) { // 所有的中间件执行完毕,执行最后回调
                last(context);
            }
        }
    }
};

执行代码:

const run = compose([middleware1, middleware2, middleware3]);

run({ a: 'a' }, () => {
    console.warn('Middlewares do last =======<');
});

输出:

middleware1 >>>>>
middleware2 >>>>>
middleware3 >>>>>
Middlewares do last =======<
middleware3 <<<<<
middleware2 <<<<<
middleware1 <<<<<

总体思路

  1. 将所有中间件推送到一个数组中
  2. 第一个中间件首先执行
  3. 在第一个中间件执行前,将第一个中间件中的 next 参数设置为一个触发下一个中间件执行的函数
  4. 第一个中间件调用 next 函数,把执行器交给下一个中间价
  5. 循环往复,直最后一个中间件执行完毕
  6. 所有中间件执行完毕后,依次执行next外层代码

优点

  • 解决多重回调地狱模式
  • 统一处理上下文context挂载与传递
  • 异常捕获

    缺点

  • 当一个项目中存在多个中间件时,对于性能会有一定影响,对于优化来说是一种考验

参考资料


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

查看所有标签

猜你喜欢:

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

文明之光

文明之光

吴军 / 人民邮电出版社 / 2014-12 / 177元

吴军博士从对人类文明产生了重大影响却在过去被忽略的历史故事里,选择了有意思的几十个片段特写,以人文和科技、经济结合的视角,有机地展现了一幅人类文明发展的宏大画卷。 《文明之光》系列大致按照从地球诞生到近现代的顺序讲述了人类文明进程的各个阶段,每个章节相对独立,全景式地展现了人类文明发展历程中的多样性。《文明之光》系列首册讲述从人类文明开始到近代大航海这一历史阶段,共八个专题。第二册讲述了从近......一起来看看 《文明之光》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试