#52 中间件模式


  • 0

    @胡子大哈 咋感觉通过的代码只能支持同步呢,真实的实现也是这样子的嘛?


  • 1
    administrators

    @Sunjourney 有同步有异步,Redux 这类是应该是同步的。Koa 异步的,异步的可以搞个 (二)。


  • 3

    写的好复杂的样子。。明明一个reduce就能解决问题的

    const app = {
      callback (ctx) {
        console.log(ctx)
      },
      
      use (fn) {
        app.middleware = app.middleware || []
        app.middleware.push(fn)
      },
      
      go (ctx) {
        app.middleware = app.middleware || []
        app.middleware.reverse().reduce((p, c) => () => c(ctx, p), () => app.callback(ctx))()
      }
    }
    

  • 1
    administrators

    @CodeHz 你改成 reduceRight 连 reverse 都省了


  • -1

    @胡子大哈 我习惯reverse()+reduce()。因为这样看起来比较统一(都是小写字母)。。


  • 0

    const app = {
      callback (ctx) {
        console.log(ctx)
      },
    
      use (fn) {
        app.middlewares = (app.middlewares || []).concat(fn)
      },
    
      go (ctx) {
        let index = 0
        this.use(this.callback)
    
        const next = () => {
          if (index < app.middlewares.length) {
            app.middlewares[index++](ctx, next)
          }
        }
    
        next()
      }
    }
    

    -> 数据经过中间件以后并不正确,中间件也许没有被正确调用

    请问,这样的写法报错的原因是什么?


  • 0
    administrators

    @Sunjourney 穿插着 go 和 use 来使用看看,应该是这个问题。


  • 0

    @ScriptOJ 确实,但是中间件应该具有这种功能吗?写测试的时候基于什么样的考虑要写这个测试呢


  • 0
    administrators

    @Sunjourney 运行阶段强插中间件的情况比较少见,但也不是不可能;但中间件的 go 多次调用几乎肯定出现,例如 koa 中间件,每一次请求过来都相当于调用了一次 go。你这里的 go 每次都 use 一下 callback 估计不大妥。


  • 1

    const app = {
      k:[],
      callback (ctx) {
        console.log(ctx)
      },
      
      use (fn) {
        this.k.unshift(fn);
      },
      
      go (ctx) {
        this.k.reduce((f,n)=>ctx=>{n(ctx,()=>f(ctx));},this.callback)(ctx);
      }
    }
    

  • 0

    @CodeHz 那为啥不用unshift+reduce呢


  • 0

    @CodeHz
    请问一下,reduce中的第二个参数可以为函数?


  • 0

    const app = {
      q:[],
      flag:true,
      ctx:{},
      callback (ctx) {
        console.log(ctx)
      },
      
      use (fn) {
        let next = ()=> this.flag = true;
        this.q.push(()=>{fn(this.ctx,next)});
      },
      
      go (ctx) {
        this.ctx = ctx;
        let q = this.q;
        console.log(q);
        for(let i = 0,len = q.length;i<len;i++){
          if(this.flag){
            this.flag = false;
            q[i]();
          }else{
            break;
          }
        }
        if(this.flag){
          this.callback(this.ctx);
        }
      }
    }

  • 0

    const app = {
      fns: [],
      callback (ctx) {
        console.log(ctx)
      },
      use (fn) {
        this.fns.push(fn)
      },
      go (ctx) {
        let nexts = []
        let idx = 0
        this.fns.forEach((fn, index) => {
          nexts[index] = () => { idx++ }
          if (idx === index) fn(ctx, nexts[index])
        })
        if(this.fns.length === idx) this.callback(ctx)
      }
    }
    

  • 0

    var app = {
      middlewares:[],
      callback (ctx) {
        console.log(ctx)
      },
      
      use (fn) {
        /* TODO */
        this.middlewares.push(fn);
      },
      
      go (ctx) {
        /* TODO */
        var flag;
        function next(){
          flag = true;
        }
        
        this.middlewares.push(this.callback);
        this.middlewares.every(function(fn){
          flag = false;
          fn(ctx, next);
          return flag
        });
      }
    }
    

    请教各位大神,这种写法下哪种用例过不去呢?


  • 1

    const app = {
      middlewares: [],
    
      callback (ctx) {
        console.log(ctx)
      },
      
      use (fn) {
        this.middlewares.push(fn)
      },
      
      go (ctx) {
        const middlewares = [...this.middlewares]
        const l = middlewares.length
    
        const dispatch = i => {
          if (i === l) {
            return this.callback(ctx)
          }
    
          middlewares[i](ctx, () => dispatch(i + 1))
        }
    
        dispatch(0)
      }
    }
    
    
    const app = {
      middlewares: [],
    
      callback (ctx) {
        console.log(ctx)
      },
      
      use (fn) {
        this.middlewares.push(fn)
      },
      
      go (ctx) {
        return [...this.middlewares].reduceRight((acc, f) => () => f(ctx, acc), () => this.callback(ctx))()
      }
    }
    
    

  • 0

    const app = {
      lastFunc: null,
      middleFunc: [],
      currentIndex: -1,
      callback(ctx) {
        console.log(ctx)
      },
      use(fn) {
        this.middleFunc.push(fn)
      },
      next() {
        this.currentIndex += 1;
        if (this.currentIndex >= this.middleFunc.length) {
          this.callback(this.lastFunc)
        } else {
          this.middleFunc[this.currentIndex](this.lastFunc, this.next.bind(this));
        }
      },
      go(ctx) {
        this.currentIndex = -1;
        this.lastFunc = ctx;
        this.next()
      }
    };
    

  • 0

    @CodeHz 使用 reverse+reduce 的中间件执行顺序和 reduceRight 是有差异的

    app.use((ctx, next) => {
      ctx.a = 1
    console.log(1)
      next()
    })
    
    app.use((ctx, next) => {
      ctx.b = 2
    console.log(2)
      next()
    })
    
    app.go({}) // => {a: 1, b: 2}
    
    app.use((ctx, next) => {
      ctx.c = 3
    console.log(3)
      next()
    })
    
    app.go({}) // => {a: 1, b: 2, c: 3}
    >1
    >2
    >{a: 1, b: 2}
    >2
    >1
    >3
    >{b: 2, a: 1, c: 3}
    
    

  • 0

    0_1549358783709_#52 中间件模式.png
    这题怎么能是中等难度呢...


  • 0

    // 参考了下koa对中间件的处理源码
    const app = {
      callback (ctx) {
        console.log(ctx)
      },
      
      use (fn) {
        /* TODO */
        this.queue = this.queue || [];
        this.queue.push(fn);
      },
      
      go (ctx) {
        /* TODO */
        if (!this.queue) {
           this.callback(ctx);
    	     return;
    	  }
        this.queue.push(this.callback);
        const compose = (middleware) => {
          return function (context, next) {
    	    // last called middleware #
    	    let index = -1
    	    return dispatch(0)
    	    function dispatch (i) {
    	      index = i
    	      let fn = middleware[i]
    	      if (!fn) {
    	      	return;
    	      }
    	      if (i === middleware.length) {
    	      	fn = next
    	      }
    	      return fn(context, dispatch.bind(null, i + 1));
    	    }
    	  }
        }
        compose(this.queue)(ctx);
        this.queue.pop();
      }
    }
    

登录后回复
 

与 ScriptOJ 的连接断开,我们正在尝试重连,请耐心等待