Skip to content

Instantly share code, notes, and snippets.

@darrenscerri
Last active July 11, 2023 02:59
Show Gist options
  • Save darrenscerri/5c3b3dcbe4d370435cfa to your computer and use it in GitHub Desktop.
Save darrenscerri/5c3b3dcbe4d370435cfa to your computer and use it in GitHub Desktop.
A very minimal Javascript (ES5 & ES6) Middleware Pattern Implementation
var Middleware = function() {};
Middleware.prototype.use = function(fn) {
var self = this;
this.go = (function(stack) {
return function(next) {
stack.call(self, function() {
fn.call(self, next.bind(self));
});
}.bind(this);
})(this.go);
};
Middleware.prototype.go = function(next) {
next();
};
class Middleware {
use(fn) {
this.go = (stack => next => stack(fn.bind(this, next.bind(this))))(this.go);
}
go = next => next();
}
// Inspired by: https://github.com/kolodny/exercises/tree/master/middleware
var middleware = new Middleware();
middleware.use(function(next) {
var self = this;
setTimeout(function() {
self.hook1 = true;
next();
}, 10);
});
middleware.use(function(next) {
var self = this;
setTimeout(function() {
self.hook2 = true;
next();
}, 10);
});
var start = new Date();
middleware.go(function() {
console.log(this.hook1); // true
console.log(this.hook2); // true
console.log(new Date() - start); // around 20
});
@yejinjian
Copy link

Inspired by you,I update my pipeline.js,like this:

util.js

/**
 * 数据去重
 * @param arr
 * @returns {any[]}
 */
export function uniq(arr) {
    return [...new Set(arr)];
}

/**
 * 数组合并去重
 * @param arr
 * @returns {*[]}
 */
export function union(...arr){
    return uniq(arr.reduce((a,b)=> a.concat(b),[]))
}

pipeline.js

import {union} from './utils';


/**
 * 核心
 * @param ctx
 * @param next
 */
const defGo = (ctx, next) => next(ctx);
/**
 * 类似koa-compose方法
 * @param tasks
 * @param dispatch
 * @param context
 * @returns {*}
 */
export const compose = (tasks, dispatch = defGo, context) =>{
    return tasks.reduce((stack,valve) => async (ctx,next)=> await valve(ctx, stack.bind(context,ctx,next)), dispatch);
}

/**
 * 管道模式
 */
export default class Pipeline {
    #valves = [] //中间件
    #basic = (e) => e
    #go = defGo

    constructor(valves = []) {
        this.addValve(...valves);
    }

    /**
     * 最终执行函数
     * @param basic
     */
    setBasic(basic) {
        if (typeof basic !== 'function') {
            throw new Error('basic must be a function');
        }
        this.#basic = basic;
        return this;
    }

    /**
     * 添加阀门
     * @param valves
     * @returns {boolean}
     */
    addValve(...valves) {
        //合并去重
        valves = valves.filter((valve) => typeof valve === 'function');
        this.#valves = union(this.#valves, valves);
        this.#go = compose(valves, this.#go);
        return this;
    }

    /**
     * 删除valves
     */
    clearValve(){
        this.#go = defGo;
        this.#valves = [];
        return this;
    }

    /**
     * 删除阀门
     * @param valves
     */
    removeValve(...valves){
        this.#valves = this.#valves.filter((valve)=> !valves.includes(valve));
        this.#go = compose(this.#valves, defGo);
        return this;
    }

    /**
     * 执行管道中的内容
     * @param params
     * @param basic
     * @returns {*}
     */
    invoke(params, basic) {
        if(basic  && typeof basic === 'function'){
            this.#basic = basic;
        }
        return this.#go(params, this.#basic);
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment