首先看 koa会怎么对待 compose 后的中间件
https://gist.github.com/79823fb6223c11dbeaec0b17cfdb43a4
一个 koa app 通常只合成一次 fn
,合成的 fn
会在每次有新的 http 请求时被调用
返回的 handleRequest 会作为 http.createServer 的参数
以下是关键的“合成”中间件的 compose
的源码
https://gist.github.com/5e0412e2c45183876c6603f6ea7ebadc
每次 http 请求调用的 fn
即是返回的 function(context, next)
,每一个向 koa app 添加的中间件的调用以此函数内的 dispatch
的形式。dispatch
的参数为对应中间件的下标。
index
在每一次 http 请求调用 fn
的时候初始化,用以保证我们的每一个中间件仅调用一次 next
。
为了能够 catch downstream errors,dispatch
会返回一个 promise,try/catch
块中的 Promise.resolve
保证了中间件不是 async function 的情况。
合成的 fn
的第二个参数 next
相当于最后的 middleware:
https://gist.github.com/1955742d152c7e0a9c2a769e0991dbfa
以 redux-thunk 为例
https://gist.github.com/f8028235d5e6f73cd2bcb93b8987556d
每个 middleware 会接收两个方法 dispatch
and getState
作为 named arguments。传递方法来获得 store state 来保证每个 middleware 获得的 state 为最新的。
形如 ({ dispatch, getState }) => next => action => {}
再来看 redux 注册中间件的方式
https://gist.github.com/5d3b23c9aef1e15a95ad3d6242ca5fe5
redux 根据中间件将原本的 dispatch
包装起来了,实现的关键部分是 compose
函数
https://gist.github.com/d6f7e6928c791373a2c9e82c17d6fc1d
compose
的每个参数都形如 next => action => {}
,最后合成的结果也是同样形式。
每一个原来的中间件都接收其右的中间件作为其 next
参数,最右的中间件的 next
参数为合成的中间件接收的 next
参数(原来的 dispatch
)