中间件是什么?
首先它是一个组件, 其次, 它与具体的业务逻辑是解耦的, 业务逻辑经常需要调用底层逻辑或者一些系统通用逻辑, 然而每次都需要去编写这些接口和代码是没有必要的, 这时候中间件就可以出场了.
具体的场景是可以看做如下: 前端业务需要某个服务, 我无需关心提供这项服务的具体底层逻辑, 只需要通过中间件获取到结果就好了
具体的例子
我们开发了一个很简单 webserver, 现在需要把不同 url 的请求路由到不同的业务处理 模块, 一开始我们的请求路径很少, 直接用 switch 语句就可以应付了, 后面随着路径越来越多, 每次都要改这个往这个 switch 加 case, 后面需求越来越变态了, 竟然要根据url路径中的参数(如用户 id 或者商品 id)路由到不同的 handler 方法, 显然我们的路由逻辑越来越复杂了
作为一个开发者, 关于如何处理好的路由的显然不是我最关心的(我只想好好地写业务代码), 那么这时候如果有一个第三方(路由中间件), 只需要传入请求的匹配规则, 对应的 handler 函数, 至于如何把请求路由到正确的 handler 中, 那是路由中间件的事情了, 之后就可以愉快的写业务代码了
中间件的模型与机制
1. 洋葱模型 (代表作 koa)
首先来两张egg.js 官网的原理图帮助简单明地去理解
洋葱模型:
中间件执行顺序:
通过上面的图看以看出, 所有的请求都会经过中间件两次, 先依次的进入中间件, 遇到 yield 退出来,执行下一个中间件, 反过来一个个往上面冒泡执行中间件yield 后面的代码, 这样子好处就是可以非常简单实现了后置处理逻辑, 比如想对返回的结果加一层封装就可以很简单的实现了
下面来学习一下如何去实习,
提前了解几个知识点:
Generator http://es6.ruanyifeng.com/#docs/generator
Promise http://es6.ruanyifeng.com/#docs/promise
Thunk函数 http://es6.ruanyifeng.com/#docs/generator-async#Thunk-函数
可以点击去回顾温习一下
简单的实现:
1 | function* f1() { |
输出结果为:
1 | f1: pre next |
再看看 koa 实现的源码
1 | // 很简单就一行 |
也太简单了吧, 继续深入挖掘一下, 我们这里再重现一下
1 | // compose 的作用就是把 compose([f1, f2, ..., fn])转化为fn(...f2(f1(noop()))) |
看到这里可能会问 co 是什么? https://github.com/tj/co 可以看一下官网的 readme, 同时源代码很少很精巧. co 是一个函数库, 可以帮助我们不用自动执行 generator 函数, 不需要我们手动执行 next() 方法.
有两种方式可以自动执行 Generator
- Thunk
- Promise 对象
co 模块其实就是将两种自动执行器集合到一起去了(Thunk 函数和 Promise 对象)
下面分别用用 Thunk 函数简单的实现 co 的原理
1 | // Promise 版本的 co |
小结:
使用 洋葱模型的 中间件很多, 比较有名就是 koa 的, 阿里出品的 egg 也是基于这个模式的, 前端的 Redux 中间件也是基于这个模型的, 本质上就是捕捉store.dispatch(action), 然后在dispatch 前后执行一些操作,比如记录日志
2. 瀑布流模型 (代表作 connect )
虽然 “洋葱模型” 的中间件功能很强大, 也很符合中间件的设计逻辑, 但是”瀑布流模型”(connect) 结合 express中间件理念的设计, 我还是更加喜欢这种瀑布流方式的中间件设计方法
具体的代码可以参考 https://github.com/senchalabs/connect#readme connect 是一个中间件的库 , express 的中间件就是这个东西
在 express 中, 一个完整个应用就是各种调用中间件
1 | app.use(function(request,response,next){ |
而这种调用方式也是十分优美的, 一个接着一个,顺序调用, 这与 express 框架的设计哲学相辅相成.
实现起来没有洋葱模型的 koa 那么炫酷,比较朴素 ,源码有284行, 精简一下,中间件相关代码如下:
1 | // 中间件本身是一个函数 |
简单的来说express 的 connect 中间件功能并不入如洋葱模型的 中间件强大, 但是优势是结合了 express 框架的基于中间件运行的理念 , 在开发使用上面也能够得心应手
小结
本篇文章是最近了解 koa 和 egg.js 之后, 对 Web前端Server框架学习与探索 文中中间件部分的一个展开了解, 在学习的过程中, 也更加深刻的理解 generator 异步编程以及基于co 这个库一些异步编程应用