原文地址: https://monster1935.com/2019/...
状态管理方案以前仅仅接触过 Vuex, 使用 React 开发时,不免要调研一下 React 技术栈下的状态管理方案,发现有 Redux 和 Mobx 相关流派。如下内容仅针对 Redux 展开讨论。javascript
在使用 Redux 的过程当中发现,有这么几个知识点仍是比较容易接受:html
store.getState()
拿到最新的状态此时有这样一个疑问: 上面仅仅讨论了一个同步的状况,对于一些异步以及存在其余反作用的 action 产生过程如何处理,带着这个疑问,看了官方文档以及一些 Demo 实现。这个过程出现了 redux-thunk、redux-promise、 redux-saga 等处理方案。这些又是作什么的,分别都解决了什么问题?java
这就要讨论一下 Redux 的中间件机制,在 Redux 中有这样一个 API, applyMiddleware
, 主要用于注册 Redux 中的中间件。redux
阅读文档的过程当中,主要搞清楚了一个最基本的世界观问题: Redux 的中间件是用来作什么的?它提供的是位于 action 被发起以后,到达 reducer 以前的扩展点。 也就是以上讨论的 redux-thunk、redux-promise、redux-saga 等都是一个个的 Redux 的中间件,使用时须要在 Redux createStore
时注册,他们分别加强了 Redux dispatch 的能力。一样能够理解为:在应用这些中间件后,使用的 dispatch 已经不是 Redux 本来的 dispatch,都是经这些中间件改写后的 dispatch。这样咱们就能再真正产生 action 以前作一些反作用的封装。promise
以 redux-thunk 为例,咱们能够清晰的的看清楚这个过程。app
function createThunkMiddleware(extraArgument) { return ({ dispatch, getState }) => (next) => (action) => { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); }; } const thunk = createThunkMiddleware(); thunk.withExtraArgument = createThunkMiddleware; export default thunk;
以上就是 redux-thunk 这个库的源码部分,「短小精悍」这个词来形容这个库一点都不过度了。究其实现,能够发现,redux-thunk 这个中间件主要是提供了 dispatch 一个 function 的能力。正常来讲 Redux 的 dispatch 仅仅能 dispatch 一个纯js对象,也就是 action。 使用 redux-thunk 后,咱们能够接收一个 function, 这个 function 会被获得调用,并被传入 dispatch 这个参数,真正的 dispatch 发生在这个 function 内部。异步
至于 Redux 的中间件机制是如何实现的,在看了其源码实现后,更是巧妙。函数
首先咱们要明确一下 「中间件」 这个概念。我的粗俗理解:中间件就是一个「管道」,只要你过了这个「管道」,都会被这个「管道」接管,「管道」不会拦住不放,而是将你「蹂躏」一番再放了你,固然也有可能不「蹂躏」你,顶多查一下户口(传说中的日志中间件)。凡是经「蹂躏」过的不论是从精神上、仍是肉体上都再也不是原来的你我,多是一蹶不振,也多是奋发图强。spa
有了以上的理解,当咱们在看这个事情的时候就好理解了。可能会有多个中间件,只要进了这个「屋」,就要依次经历这些中间件。prototype
const reduxMiddleware = ({dispatch, getState}) => (next) => (action) => { // 作一些查户口以及蹂躏相关的事情 // 放行 return next(action); }
这是一个 redux middleware 的通用实现。当咱们在 applyMiddleware
时发生了什么?
const chain = middlewares.map(middleware => middleware({ getState: store.getState, dispatch: (action, ...args) => dispatch(action, ...args), })); const dispatch = compose(chain)(store.dispatch); return { ...store, dispatch }
大体意思就是将全部的 middleware 传入,并经过 compose
这个函数将全部的中间件组合并返回一个 dispatch
函数, 此时的 dispatch
不是 redux 本来的 dispatch 实现,而是一个经中间件加强了的 dispatch,这里面有一个控制权的反转,即将本来的 dispatch 功能做为参数传入,在函数内部完成 dispatch 的逻辑。此时的 dispatch 多是这样的:
const dispatch = (dispatch) => { // do things // 这里通过了全部注册过的中间件的处理 // do things return action => dispatch(action); }
Redux 中间件实现的关键是 compose
函数,compose
函数利用 Array.prototype.reduce()
API,完成全部中间件函数的依次调用,并返回如上所示的一个函数。
function compose(funcs) { return function (dispatch) { if (funcs.length === 1) { return funcs[0]; } return funcs.reduce((a,b) => (...args) => a((b(...args)))); } }
如上即是整个中间件机制的实现过程。由于中间涉及到一些函数柯里化的内容,有些函数嵌套较深才能返回,若是感受到晦涩,能够看这个简洁版的代码:
// 这是一个中间件 const a = (next) => (action) => { console.log('通过了 a 中间件的蹂躏'); return next(action); }; // 这是一个中间件 const b = (next) => (action) => { console.log('通过了 b 中间件的蹂躏'); return next(action); }; // 这是一个中间件 const c = (next) => (action) => { console.log('通过了 c 中间件的蹂躏');; return next(action); }; // 原版的 dispatch var rawDispatch = (action) => { console.log('终于轮到原生的dispatch action了,派发了: ', action); return action; } /** 如下是 applyMiddlware 的实现原理, 开始注册中间件 */ var arr = [a, b, c]; var res = arr.reduce((a, b) => (...args) => a(b(...args))); var enhanceDispatch = res(rawDispatch); // 调用一个加强的dispatch,会发现中间件逻辑会一次处理 enhanceDispatch('add'); // 通过了 a 中间件的蹂躏 // 通过了 b 中间件的蹂躏 // 通过了 c 中间件的蹂躏 // 终于轮到原生的 dispatch action了,派发了: add // "add"
参考连接: