zoukankan      html  css  js  c++  java
  • koa-compose源码分析

    koa-compose是koa中间件的核心部分, 控制着中间件的执行流程, 造就了经典的洋葱模型。
    module.exports = compose​
    
    function compose(middleware) {
        //首先是参数类型检查,不符合就抛错
        //middleware必须是数组
        if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
            //middleware的项必须是函数
        for (const fn of middleware) {
            if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')
        }​
    
        // 返回一个闭包, 保持对 middleware 的引用
        return function(context, next) {
            let index = -1
            //从中间件第一项开始,执行中间件函数
            return dispatch(0)
    
            function dispatch(i) {
                //索引小于等于index,说明一个中间件函数中next被调用多次,不允许
                if (i <= index) return Promise.reject(new Error('next() called multiple times'))
                //index更新为i,对应前面的检测
                index = i
    
                //取出中间件中的第i个函数
                let fn = middleware[i]
                //如果索引到数组最后,函数变成next,不明白???
                if (i === middleware.length) fn = next
                //遍历结束,fn为undefined,返回Promise,方便后面thenable
                if (!fn) return Promise.resolve()
                try {
                    //关键部分,fn中传入context和next函数,对应于app.use((ctx,next) => {...})的用法
                    //Promise.resolve让返回值支持thenable调用
                    return Promise.resolve(fn(context, function next() {
                        //尾递归dispatch,索引加1,不断调用中间件的下一个函数,直至用尽
                        //尾递归可以提升效率,缩短call Stack
                        //递归是洋葱模型的关键,递归本身的call Stack就是按照洋葱模型来执行
                        //next之前执行代码,在next时候调用下一个中间件,下一个中间件继续执行next之前代码,next执行下下个中间件
                        //等到递归完成,到最后一个中间件,开始出栈,先执行最里面的next之后的代码,以此往外执行,形成洋葱调用
                        return dispatch(i + 1)
                    }))
                } 
                catch (err) {
                    //如果递归调用中抛错,就reject
                    return Promise.reject(err)
                }
            }
        }
    }

  • 相关阅读:
    Spring Bean的生命周期
    使用docker安装虚拟机并打开ssh连接
    查看/设置JVM使用的垃圾收集器
    使用Apollo动态修改线上数据源
    java8之lambda表达式
    Java8之Stream
    @Bean 的用法
    Java中的Filter过滤器
    详解tomcat的连接数与线程池
    什么是ClassLoader
  • 原文地址:https://www.cnblogs.com/mengff/p/12857386.html
Copyright © 2011-2022 走看看