美文网首页web前端
中间件的原理

中间件的原理

作者: 姜治宇 | 来源:发表于2020-04-06 19:48 被阅读0次

    我们在使用express框架的时候,经常遇到中间件。
    中间件给人的感觉是非常好用的,那么它的原理是怎样的呢?今天我们试着写一下看看。
    我们要实现的大概是这样一个东西:

    
    function myexpress() {
    
    
    }
    
    
    var app = myexpress();
    
    function middlewareA(req, res, next) {
        console.log('middlewareA before next()');
        next();
        console.log('middlewareA after next()');
    }
    
    function middlewareB(req, res, next) {
        console.log('middlewareB before next()');
        next();
        console.log('middlewareB after next()');
    }
    
    function middlewareC(req, res, next) {
        console.log('middlewareC before next()');
        next();
        console.log('middlewareC after next()');
    }
    //注册回调函数
    app.use(middlewareA);
    app.use(middlewareB);
    app.use(middlewareC);
    //调用
    app()
    

    思路大家应该可以想到,还是利用观察者模式:
    use订阅回调函数,在next触发。
    不过有两个问题大家可以先思考一下:

    1、myexpress返回什么?
    2、怎么执行订阅的回调函数?

    先看第一个问题。这里令人困惑的地方是:
    myexpress得具有use方法,同时还得是个闭包函数才行。

    var app = myexpress()
    app.use(...)//app得具有use方法
    app()//闭包
    

    如果myexpress返回的是一个对象:

    function express() {
        var subs = []
        return {
            use:function(cb){
                subs.push(cb)
            }
        }
    
    }
    var app = express()
    app.use(function(){
        console.log('test')
    })
    app()//出错了~~
    

    如果是闭包,那use方法就没地方放了:

    function express() {
        var subs = []
        return function(){
            
        }
    
    }
    var app = express()
    app.use(function(){//出错了~~
        console.log('test')
    })
    app()
    

    咋办呢?
    其实很简单,闭包我们通常习惯使用匿名函数,自然无法再多追加use方法,而使用具名函数即可解决这个问题。

    
    function express() {
        var subs = []
    
        var func = function(){//具名函数
    
        }
        func.use = function(cb){//具名函数下追加use方法
            subs.push(cb)
        }
        return func //返回具名函数
    
    }
    var app = express()
    app.use(function(){
        console.log('test')
    })
    app()
    

    下面看第二个问题。
    观察者的订阅场景比较清晰,就是在调用use的时候注册回调函数;但触发场景有点令人困惑,因为它是在回调函数内部调用next的,如何捕获并执行到next呢?
    这其实还是高阶函数的问题,在手写promise时也遇到过:

    
    function express() {
        var subs = []
    
    
        var func = function(){//具名函数
    
            function next(){
                var cb = null
                if(subs.length>0){
                    cb = subs.shift()//出列一个回调函数
    
                    cb(next)//高阶函数最终执行的是他!
    
                } else {
                    return;//如果队列为空,返回
                }
            }
            next()//app()时开始执行
    
        }
        func.use = function(cb){//具名函数下追加use方法
            subs.push(cb)
        }
        return func //返回具名函数
    
    }
    var app = express()
    app.use(function(next){
        console.log('test')
        next()
    })
    app()
    

    这样最终代码也就写出来了:

    
    function express() {
        var subs = []
    
    
        var func = function(){//具名函数
    
            function next(){
                var cb = null
                if(subs.length>0){
                    cb = subs.shift()//出列一个回调函数
    
                    cb(next)//高阶函数最终执行的是他!
    
                } else {
                    return;
                }
            }
            next()//app()时开始执行
    
        }
        func.use = function(cb){//具名函数下追加use方法
            subs.push(cb)
        }
        return func //返回具名函数
    
    }
    var app = express()
    function middlewareA(next) {
        console.log('middlewareA before next()');
        next();
        console.log('middlewareA after next()');
    }
    
    function middlewareB(next) {
        console.log('middlewareB before next()');
        next();
        console.log('middlewareB after next()');
    }
    
    function middlewareC(next) {
        console.log('middlewareC before next()');
        next();
        console.log('middlewareC after next()');
    }
    
    app.use(middlewareA);
    app.use(middlewareB);
    app.use(middlewareC);
    
    app()
    

    相关文章

      网友评论

        本文标题:中间件的原理

        本文链接:https://www.haomeiwen.com/subject/rjcuphtx.html