• koa-中间件流程控制


    koa中间件执行流程

    koa中间件的的执行顺序是洋葱模型,外层逐步向内,执行到最中间再逐步向外扩展,实现这个顺序的模型需要依赖于generator函数,它可以暂停执行将控制权交出,等到执行next再得到执行权继续执行,我们需要做的就是将generator串联起来,将后面的generator函数跟在上一层函数的yield语句之后,可以看作后面的函数是next的参数,这样我们就形成了一个串联,它的执行顺序就是我们前面所提到的洋葱模型。

    koa-compose

    在koa中,实现上面所说的串联函数就是利用了compose,下面是compose的大概实现(在koa中叫koa-compose):

    function compose (middlewares) {
        return function (next) {
            var i = middlewears.length;
            var next = function* () {}();
            while (i--) {
                next = middlewares[i].call(this, next); 
            
                <!--这一点不太好理解:首先这是个递减的过程,我们会先取到最后的一个函数
                然后,next函数其实是起到一个中介的作用,将next传入后又重新更新了next
                也就是在下一此的运行中next函数是带有刚刚那个最内层的函数的(最后一个)
                于是再进行操作,是一个递归传入的过程,可以看这篇文章:https://cnodejs.org/topic/5723360e35af8a704195f5d5
                -->
            }
            return next;
        }
    }    
    

    在koa的源码中有这样的代码:

    var fn = this.experimntal
        ? compose_es7(this.middleware)
        : co.wrap(compose(this.middleware));
    

    我们添加中间件的时候使用app.use方法,其实这个方法只是把中间件push到一个数组,很明显,所有的中间件在数组中,那么它们之间是没有联系的,所以我们会看到上面的代码,将所有的中间件都传入了我们所说的compose中。经过compose转换的代码是下面这样

    //达到了洋葱模型的效果
    function *() {
        yield *g1(g2(g3()))
    }
    

    co模块

    上面我们看到通过使用koa-compose将中间件联系在一起(串联),可是在koa中需要调用next()方法才可以驱动函数向下执行。这时候就需要用到co模块。它可以帮我们自动管理generator的next,并根据调用返回value做出不同的响应;如果遇到另外一个generator,co会继续调用自己,这就是我们为什么需要co。
    简单实现原理:

    function run (gen) {
        var g;
        if (typeof gen.next === 'function') {
            g = gen;
        } else {
            g = gen();
        }
        function next () {
            var tmp = g.next();
            if (tmp.done) {
                return;
            } else if (typeof g.next === 'function') {
                run(tmp.value);  // 将下一步传入run函数当中
                next();
            }
        } 
        next();
    }
    

    通过递归的方式(判断是否执行结束),来驱动generator的执行。

    关于co模块的补充(es6)
    • co会返回一个Promise对象,因此我们可以使用then方法添加回调函数
    • co真正的源码做了什么
      • 检查当前代码是否为Generator函数的最后一步,如果是就返回
      • 确保每一步返回的结果都是promise对象
      • 使用then方法为返回值加上回调函数,然后通过onFulfilled函数再次调用next函数
      • 在参数不符合要求的情况下将promise状态改为Rejected从而终止模块。

    ps:理解有限,如果有误请指出!

  • 相关阅读:
    痞子衡嵌入式:i.MXRT1010, 1170型号上不一样的SNVS GPR寄存器读写控制设计
    痞子衡嵌入式:嵌入式Cortex-M裸机环境下临界区保护的三种实现
    《痞子衡嵌入式半月刊》 第 36 期
    痞子衡嵌入式:嵌入式MCU中标准的三重中断控制设计
    痞子衡嵌入式:了解i.MXRTxxx系列ROM中灵活的串行NOR Flash启动硬复位引脚选择
    痞子衡嵌入式:串行NOR Flash的页编程模式对于量产效率的影响
    《痞子衡嵌入式半月刊》 第 35 期
    痞子衡嵌入式:对比i.MXRT与LPC在RTC外设GPREG寄存器使用上的异同
    Springboot 配置文件、隐私数据脱敏的最佳实践(原理+源码)
    干掉 Postman?测试接口直接生成API文档,这个工具贼好用
  • 原文地址:https://www.cnblogs.com/nanshanlaoyao/p/6686568.html
Copyright © 2020-2023  润新知