写一个简易中间件

784 阅读2分钟

目的

解决项目中代码耦合度比较高,可以随时对业务部分代码进行插拔。

API 设计

applyMiddleWare(middleWares) //middleWares 传入的中间件

返回值 fn //fn 为启动中间件的方法

支持复合调用 applyMiddleWare(middleWare1, applyMiddleWare(middleWares), .....)

实现

我们假定有三个中间件:add, substract, multiply

顺序是 add -> substract -> multiply

单个中间件的设计是:

function MiddleWare(next) => {
    return function(str){
        next(str)
    }
    
}

next为下一个启动中间件的方法,思路其实很简单,就是把multiply 的 里面一层即 function(str){ next() } 这一层作为substract 的next,再依次往上挂,所以我们可以写下如下代码

function applyMiddleWare(middleWares){
        var next = function(str){
            return str;
        };
        middleWares = middleWares.reverse();
        for(var i=0; i<middleWares.length; i++){
            var next = middleWares[i](next);
        }
        return next;
    }
」    

至于最里面的那一层没有next,我们又是从后往前遍历中间件,所以入口的next 返一个 var next = function(str){ return str;}这个就好了,把处理的结果抛上去。

至于middleware复合的情况会有一点复杂,我们举个例子: applyMiddleWare(middleWare1, applyMiddleWare(middleWares)) middleWare1 的结构是 (next) => (str) => {}, applyMiddleWare(middleWares)的结构是 (str) => {}。我比较偷懒,打算把所有的组合都作为普通中间件,这里用了一个contents记录组合的中间件的,例如:

var start = applyMiddleWare(middleWares1, middleWares2, middleWares3);

那么start的contents 就是[middleWares1, middleWares2, middleWares3],对于组合和非组合的用content字段区别,统一展开,类似数组展平,具体实现如下:

function add(next){
    return function (str){  
        console.log('add中间件before(准备+2):', str);  
        str += 2;
        str = next(str);
        console.log('add中间件after:', str);  
        return str;
    }
}

function subtract(next){
    return function(str){
        console.log('subtract中间件before(准备-1):', str);  
        str -= 1;
        str = next(str);
        console.log('subtract中间件after:', str);
        return str;  
    }
}

function multiply(next){
    return function(str){
        console.log('multiply中间件before(准备*2):', str);  
        str *= 2;
        str = next(str);
        console.log('multiply中间件after:', str); 
        return str; 
    }
}

function flattenMiddleWare(middleWares){
    var _array = [];
    for(var i=0; i<middleWares.length; i++){
        if(middleWares[i].isContents){
             _array.push(...flattenMiddleWare(middleWares[i].isContents))
        }else{
            _array.push(middleWares[i]);
        }
    }
    return _array;
}

function applyMiddleWare(middleWares){
    var next = function(str){
        return str;
    };
    middleWares = flattenMiddleWare(middleWares).reverse();

    for(var i=0; i<middleWares.length; i++){
        var next = middleWares[i](next);
    }
    next.isContents = middleWares;
    return next;
}

function extraDivideMiddle(next){
    return function(str){
        console.log('divide中间件before(准备/0.5):', str);  
        str /= 0.5;
        str = next(str);
        console.log('divide中间件after:', str); 
        return str; 
    }
}

//测试
var result = applyMiddleWare([extraDivideMiddle, applyMiddleWare([add, subtract, multiply]), extraDivideMiddle])(10);
console.log('result:', result);

结果