聊聊 Redux 和 Koa 的中间件

1,206 阅读4分钟

何为中间件

我理解的中间件是一种能够将数据进行管道化处理的编程技术,每个中间件负责处理一部分数据,最终组合成一条具有数据处理能力的管道。这种编程技术最早可能来自于函数式编程领域,在前端技术领域中最知名的应用案例当属于 Redux 和 Koa 这两个库,网上有很多分析两个库关于中间件的源码实现,但鲜有文章分析两者设计上的区别,于是就有了这篇聊聊

中间件管道的设计

Redux

如果你探究过两者的源码,应该不难发现同样是中间件,但是两者在构建中间件管道上采用了两种不同的编程技术,Redux 使用的是源于 reduce 函数,通过特定的中间件函数签名,将中间件函数不断合并最终变成一个阶梯式的嵌套函数,这个嵌套函数就是被包装过的 dispatch ,有意思的是,如果中间内部调用了 dispatch 则整个嵌套函数会被重新执行,这个特性保证了所有中间件的有序执行,但如果你的中间件中有异步代码,那就会变得有点不如预期,甚至有点糟糕了,由此我们可以得到一个设计上的结论,Redux 的中间件管道是同步处理所有的数据,同时它也支持重置整个处理流程,实现上通过函数嵌套而非递归,执行顺序上有很有意思,第一个中间件的next函数的之前的代码最先执行,next函数之后的代码则最后执行,整个中间件管道其实是基于next函数链的一个环形管道,可以得到如下这张图。

Koa

相比 Redux 中间件的复杂机制,Koa 实现上就简单多了,非常直接的递归实现,然后就是对中间件函数的一些限制,比如不能调用两次的 next, 不然就给你一个大大的 Error :-{ ,同时为了解决异步中间件的问题, Koa 引入了 async/await,从执行机制上抹平了同步异步代码的差异, 当然前提是你按照规范书写你的代码,不同于 Redux 的中间通过传递处理后的 action 的击鼓传花,Koa 通过向所有中间件注入 ctx 对象完成数据的处理。

让我们总结下

从 Redux 的角度,中间件的机制是为了扩展 action 装载数据的能力,毕竟在 FLUX 架构中,action 非常简单却又极其重要,正因为 action 被设计的很简单,当我们需要完成复杂的功能,就需要一种强大的扩展 action 能力,能够让 action 装载不同类型的数据,甚至是函数,从而将整个应用的数据流能够管理起来,而不至于因为 action 无法装载某种数据,导致数据流的泄露。这种设计理念也同样适用于对 Redux 中间件的设计, 当我们考虑将某些通用的功能或者业务放在 Redux 中间件中去实现和处理的时候,不应该将中间件定义为某种业务功能,而应该从 action 的角度去设计中间件,从处理所有的 action 和 处理某种具有明确语义的 action 这两点来设计我们的中间件,即中间件本身存在两种大的类型

  • 全局 action 处理,例如 logger
  • 具有明确语义的 action 处理,可分为两类
    • 业务型, 例如 埋点的处理
    • 功能型, 例如 thunk, promise

不同于 Redux 只传递一个 action,Koa 要处理的是一对 Req/Res 数据模型,它的类型是不可变的,即我们不能设计说有一种全局的 Req/Res,有一种业务的,我们会说 Koa 的中间件有全局的,业务的,因为设计的重点在于中间件而不是中间件处理的数据,所以 Req/Res 就可以作为 ctx 的一部分成为中间件管道的上下文, 而我们设计 Koa 中间件的时候,就会把关注点放在中间件本身,而不是像 Redux 那样先考虑 action 的类型, 再定义中间件,所以 Redux 和 Koa 中间件的最大区别,我想用一句话就足以概括了。

In Reudx is ActionMiddleware,In Koa is Middleware

打个小广告:挖财 无线 & 前端团队求贤若渴,如果你喜欢各种新奇的 Cool 的技术,喜欢捣鼓各种工具, 喜欢研究架构,本团队提供各种环境和机会,欢迎简历来投,流程超快,当天出签,急速入职!!!