中间件模式

作者: 千茉紫依 | 来源:发表于2019-04-01 20:08 被阅读0次

中间件模式被广泛应用在 Koa框架中,它允许在调用目标函数之前,随意插入其他函数预先对数据进行处理、过滤。在这个过程里面你可以打印数据、或者停止往下执行中间件等。数据就像水流一样经过中间件的层层的处理、过滤,最终到达目标函数。请你模拟一个中间件模式,可以达到以下效果:

const app = {
  callback (ctx) {
    console.log(ctx)
  },
  
  use (fn) {
    /* TODO */
  },
  
  go (ctx) {
    /* TODO */
  }
}

app.use((ctx, next) => {
  ctx.name = 'Lucy'
  next()
})

app.use((ctx, next) => {
  ctx.age = 12
  next()
})

app.use((ctx, next) => {
  console.log(`${ctx.name} is ${ctx.age} years old.`) // => Lucy is 12 years old.
  next()
})

// ... 任意调用 use 插入中间件

app.go({}) // => 启动执行,最后会调用 callback 打印 => { name: 'Lucy', age: 12  }

ctx 参数就是 app.go 接受的对象。调用 app.go 其实会调用目标函数 app.callback,但是调用 app.callback 之前我们可以先让参数 ctx 通过一系列的中间件,最后才会传递给 app.callback。

使用 app.use 插入任意中间件,中间件是一个函数,可以被传入一个 ctx 和 next;调用 next 的时候会执行下一个中间件。如果不调用 next 会阻止接下来所有的中间件的执行,也不会执行 app.callback。

请你补全 app 的实现,请不要添加额外的全局变量。

答案

我之前用过koa,大概知道中间件是用栈的方式实现的,也大概知道用reduce把所有函数嵌套起来返回应该就可以了,但是实际操作起来却在next函数上踩坑,完全搞不懂怎样把控制权交接给下一个函数。在查过大量资料之后,发现对于next的实现有两个简单可行的方案:

方案一:对next函数进行定义
const app = {
    midware:[],
    callback(ctx) {
        console.log(ctx);
    },

    use(fn) {
        this.midware.push(fn)
    },

    go(ctx) {
        let fnIdx=0
        const next=()=>{
            fnIdx++
        }
        this.midware.forEach((fn,idx)=>{
             if(fnIdx==idx)
             fn(ctx,next)
        });
        if(fnIdx==this.midware.length)
            this.callback(ctx)
    }
}

首先定义midware数组,每一次调用use就把中间件push进该数组。在执行go函数时,将重新定义的next方法加入fn中执行。若某一中间件中没有定义next()函数,那么他之后所有中间件的fnIdx将会与idx不同,这就实现了异常退出的功能,而当所有中间件执行完毕后,fnIdx==this.midware.length等式将成立,此时调用回调函数,完成app加载。非常巧妙,值得借鉴。

方案二:使用reduce遍历
const app = {
    midware:[],
    callback(ctx) {
        console.log(ctx);
    },
    use(fn) {
        this.midware.unshift(fn)
    },
    go(ctx){
        let fn=this.midware.reduce((pre,cur)=>{
            return (ctx)=>cur(ctx,()=>pre(ctx))
        },this.callback)
        fn(ctx)
    }
}

这种方法比较常规,首先reduce的初始值为this.callback,每次遍历结束将return的值赋给pre,从而实现函数嵌套的效果,这里注意由于在中间件中next是以函数的形式存在的,所以cur的第二个参数,应该是()=>pre(ctx),这样在调用fn的时候才能正确进行迭代。

相关文章

  • 消息中间件介绍

    文章大纲 一、什么是消息中间件二、消息中间件组成三、消息队列的的传输模式四、消息中间件的优势五、消息中间件应用场景...

  • 【js】动手实现一个简单的中间件

    简单介绍一下中间件: 中间件模式(middleware)是一种很常见、也很强大的模式,被广泛应用在 Express...

  • 中间件(Middleware)

    中间件 问题1:中间件的背后的设计理念是什么?(分离横切关注功能/拦截过滤器模式)问题2:中间件有哪些不同的实现方...

  • sentinel开源限流方案—企业级二次开发方案

    存在的问题 思索2.1 需要引入zk、nacos中间件吗2.2 配置更新采用推模式还是拉模式-2.2.1 拉模式(...

  • 中间件模式

    代码示例

  • 中间件模式

    中间件模式被广泛应用在 Koa框架中,它允许在调用目标函数之前,随意插入其他函数预先对数据进行处理、过滤。在这个过...

  • 让 .NET 轻松构建中间件模式代码

    让 .NET 轻松构建中间件模式代码 Intro 在 asp.net core 中中间件的设计令人叹为观止,如此高...

  • React知识点(面试汇总)

    1、redux中间件中间件提供第三方插件的模式,自定义拦截 action -> reducer 的过程。变为 ac...

  • 让 .NET 轻松构建中间件模式代码(二)

    让 .NET 轻松构建中间件模式代码(二)--- 支持管道的中断和分支 Intro 上次实现了一个基本的构建中间件...

  • MetaQ

    MetaQ 简介: 概念:MetaQ是一款分布式、队列模型的消息中间件。 模式:分为Topic与Queue两种模式...

网友评论

    本文标题:中间件模式

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