谈谈中间件

今天就谈谈koa中的中间件
  • 人就是这样,在使用一样东西的时候,可能更多的是关注这件东西怎么去使用,或者说怎么才可以才更好的使用,但是往往这样就会忽略这件东西的源代码的实现,或者说核心原理的实现
  • 我在使用koa框架的时候,就是为了创建一个简单的http服务器来运行项目就可以了,没想别的,也没怎么深入的去理解koa中间件的原理实现,不过有一点可以确定,那就是既然koa是用javascript写的,那么,使用 javascirpt就是可以原生的写出来,没有做不到,只有想不到
  • 今天就来谈谈 koa中间件是怎么写出来的,或者说根据需求,写的思路是怎样的
先看看需求
  • 任何一个函数的出现或者诞生,都是有需求,才会诞生,没有需求的函数写出来是没有意义的
app.use(function(next){
    console.log(1)
    next()
    console.log(2)
})

app.use(function(next){
    console.log(3)
    next()
    console.log(4)
})

app.use(function(next){
    console.log(5)
    next()
    console.log(6)
})

app.compose()
  • 就像上面的例子,我有这么一个需求,中间件是通过 use这个函数来注册的,或者说通过 use这个函数来添加的,然后,通过 compose这个函数来使用中间件,或者说启动中间件,但是呢,这里有一个亮点,就是中间件的参数 next是一个函数,一旦调用这个 next函数,那么就会 启动下一个中间件,就是这么一个需求
  • 可以想到,根据需求上面里子的输出结果应该是 1,3,5,6,4,2
根据需求分析函数的实现
  • 首先看到 app实际上就是一个对象,里面肯定有两个函数,一个是 use函数,用来注册中间件的,一个是 compose函数,用来启动中间件的,那么注册的中间件会存放在哪里呢,因此肯定要有一个数组来存放已经注册的中间件满足这些条件的 app有两种设计:
单例模式设计(感觉叫对象设计也可以)
var app = {
    // 数组用于存放注册的中间件
    middlewares:[],
    // use 函数用于注册中间件
    use:function(){},
    // compose 函数用于 启用中间件
    compose:function(){}
}
闭包设计
var app = (function(){
    // 数组用于存放注册的中间件
    var middlewares = []
    return {
        // use 函数用于注册中间件
        use:function(){},
        // compose 函数用于 启用中间件
        compose:function(){}
    }
})();
  • 这两个设计的区别在于 缓存中间件的数组外界可不可以直接获取单例模式设计下 通过 app.middlewares 可以直接获取,但是 闭包设计不可以获取因为不想已经注册的中间件被外界直接修改,所以使用闭包设计会更好
use的实现
  • 因为是直接添加中间件,实现起来也比较简单:
use:function(fn){
    middlewares.push(fn)
}
compose的实现
  • 在实现之前要想明白需求一旦调用 compose函数,就会调用第一个中间件,并且一旦调用 next,那么就会启动下一个中间件
compose:function(){
    var index = 0
    // 先获取第一个中间件
    var fn = middlewares[index]
    // 因为 fn 第一个参数实际上就是 next 函数
    function next(){
        index++
        // 一旦调用 next,获取下一个中间件
        fn = middlewares[index]
        // 然后执行下一个 中间件,但是这里要先判断下一个中间件存不存在,存在才执行
        fn && fn(next)
    }
    // 执行第一个中间件
    fn(next)
}
  • 根据需求 compose函数的实现就是根据 思路写出来的,测试一下:
    在这里插入图片描述
  • 跟预想的一样,基本上中间件的核心原理就已经实现了,但是可能会觉得 代码有点丑陋,是因为 有些代码重复了,优化之后:
compose:function(){
    function donext(index){
        var fn = middlewares[index]
        fn && fn(()=>donext(index+1))
    }
    donext(0)
}
  • 很明显,优化之后的代码看起来更简洁,但是思路是一样的,至于怎么想到这么优化的,我只想说就是,靠经验,我觉得优化前的版本才是 正常人写出来的版本
完整代码
var app = (function(){
    // 数组用于存放注册的中间件
    var middlewares = []
    return {
        // use 函数用于注册中间件
        use:function(fn){
            middlewares.push(fn)
        },
        // compose 函数用于 启用中间件
        compose:function(){
            // var index = 0
            // var fn = middlewares[index]
            // function next(){
            //     index++
            //     fn = middlewares[index]
            //     fn && fn(next)
            // }
            // fn(next)
            function donext(index){
                var fn = middlewares[index]
                fn && fn(()=>donext(index+1))
            }
            donext(0)
        }
        
    }
})();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值