web前端

中间件的原理

2020-04-06  本文已影响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()
上一篇 下一篇

猜你喜欢

热点阅读