以上是整理的一些说明和文档资料,没有看过的能够去了解一下。下面将开始本文的主题:redux的中间件applyMiddleware。前端
都说名字越长,越让学者惧怕,applyMiddleware的名字看起来就挺吓人,那么为何会出现中间件,它是作什么的?它为何叫中间件?为何说能够用来解决异步dispatch?通过一段时间的了解,让我渐渐明白了它的工做原理,如今让咱们带问题,怀着简单,轻松的心态走进applyMiddleware大讲堂:react
console.log('dispatching', action);
dispatch(action)
假如又来一个产品B说,我须要记录每次数据出错的缘由,咱们怎么办呢?而后咱们又须要在对每个dispatch作修改git
try{ dispatch(action) }catch(err){ console.error('错误报告: ', err) }
若是咱们的程序中有不少的dispatch,咱们就须要添加不少的重复代码,虽然编辑器提供批量替换,但这无疑是产生了不少样板代码。
由于全部的需求都是和dispatch息息相关,因此只要咱们把日志放进dispatch函数里,不就行了吗,咱们只须要更改dispatch函数,把dispatch进行一层封装。
大概的封装就是下面这样:
github
let next = store.dispatch store.dispatch = function dispatchAndLog(action) { console.log('dispatching', action) next(action) }
Redux把这个封装的入口写成了一个函数,就叫applyMiddleware。
由此咱们明白了applyMiddleware的功能:改造dispatch函数,产生真假dispatch,而中间件就是运行在假真(dispatchAndLog假和next真)之间的代码。
这里咱们要对applyMiddleware进行一个准确的定义,它只是一个用来加工dispatch的工厂,而要加工什么样的dispatch出来,则须要咱们传入对应的中间件函数(好比上例中的dispatchAndLog),下面咱们构造一个精简版的applyMiddleware:redux
const applyMiddleware = function(middleware){ let next = store.dispatch; store.dispatch = middleware(store)(next); // 这里传入store,是由于中间件中有可能会用到getState获取数据,好比打印当前用户等需求 } applyMiddleware(dispatchAndLog)
const logger = store => next => action => { console.log('dispatching', action) return next(action) } const collectError = store => next => action => { try { return next(action) } catch (err) { console.error('Error!', err) } }
而后,咱们改造一下applyMiddleware,来接收一个middlewares数组:数组
function applyMiddleware(middlewares) { middlewares = middlewares.slice() middlewares.reverse() let dispatch = store.dispatch middlewares.forEach(middleware => dispatch = middleware(store)(dispatch) ) return Object.assign({}, store, { dispatch }) }
上面的middleware(store)(dispatch) 就至关因而 const logger = store => next => {},这就是构造后的dispatch,继续向下传递。这里middlewares.reverse(),进行数组反转的缘由,是最后构造的dispatch,其实是最早执行的。由于在applyMiddleware串联的时候,每一个中间件只是返回一个新的dispatch函数给下一个中间件,实际上这个dispatch并不会执行。只有当咱们在程序中经过store.dispatch(action),真正派发的时候,才会执行。而此时的dispatch是最后一个中间件返回的包装函数。而后依次向前递推执行。
咱们拿logger和collectError来讲明:
构造过程:react-router
let next = store.dispatch; let dispatch1 = logger(store)(next); // 这时候的console.log('dispatching', action) 是没有执行的 let dispatch2 = collectError(store)(dispatch1); // 这时候的console.log('Error!', err) 也是没有执行的 store.dispatch = dispatch2;
执行过程:app
store.dispatch(action); //假如咱们程序中派发了某个action //至关因而下面这样 dispatch2(action); //此时执行了 console.log('Error', err) //因为collectError中间件中的next是接收的logger返回函数即dispatch1,因此在开始执行 dispatch1(action); //此时执行了 console.log('dispatching', action) // 这个例子不太合理,由于错误报告是先 try 的 next(action),可是正常的流程是如此。
未完待续……异步