上一篇文章讲解了redux如何使用,本篇文章将进一步深刻,从redux的源码入手,深刻学习redux的中间件机制。
在这里咱们会以一个redux-thunk
中间件为例,逐步分解redux的中间机制如何操做,如何执行。javascript
闲话很少说,上代码。java
import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import rootReducer from './reducers/index'; // create a store that has redux-thunk middleware enabled const createStoreWithMiddleware = applyMiddleware( thunk )(createStore); const store = createStoreWithMiddleware(rootReducer);
这里须要用到redux
中提供的一个工具方法,叫作applyMiddleware
,向该方法传入你想要使用的中间件,完了以后再传入createStore
方法,
最终造成新的建立store的方法。es6
这显然是一个装饰器模式,经过不一样的中间件对createStore
方法进行修饰,最后造成新的createStore
方法,那么建立的store就具备这些中间件的特性,
很是出色的设计,惊喜不只在这,看了以后的代码你就更不得不佩服做者的代码设计能力。express
瞬间以为别人都是码神,而我就是码农有木有/(ㄒoㄒ)/~~编程
先来看applyMiddleware
方法的实现redux
import compose from './compose'; /** * Creates a store enhancer that applies middleware to the dispatch method * of the Redux store. This is handy for a variety of tasks, such as expressing * asynchronous actions in a concise manner, or logging every action payload. * * See `redux-thunk` package as an example of the Redux middleware. * * Because middleware is potentially asynchronous, this should be the first * store enhancer in the composition chain. * * Note that each middleware will be given the `dispatch` and `getState` functions * as named arguments. * * @param {...Function} middlewares The middleware chain to be applied. * @returns {Function} A store enhancer applying the middleware. */ export default function applyMiddleware(...middlewares) { return (next) => (reducer, initialState) => { var store = next(reducer, initialState); var dispatch = store.dispatch; var chain = []; var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) }; chain = middlewares.map(middleware => middleware(middlewareAPI)); dispatch = compose(...chain)(store.dispatch); return { ...store, dispatch }; }; }
这就是redux里面这个方法的源码,其中还一半是注释有木有。。。原本觉得确定有百来行代码的
固然这里不得不说es6的特性提供了很是多的帮助,因此为了省力吧es6玩透仍是灰常有必要的(更别说为了装X了(^__^) )数组
从这里开始代码就有点绕了,咱们逐行分析服务器
return (next) => (reducer, initialState) => {...}
整个applyMiddleware
方法就是返回了一个方法,根据applyMiddleware
方法的使用,咱们能够知道next
就是createStore
方法,
由于最终咱们要返回的是一个装饰过的createStore
方法,那么接收的参数确定是不会变,因此最终咱们调用createStoreWithMiddleware
方法其实就是调用app
function (reducer, initialState) { var store = next(reducer, initialState); // next即为最初的createStore方法 // ...如下省略 }
var store = next(reducer, initialState); var dispatch = store.dispatch; var chain = [];
这里没什么好讲的,首先建立了一个store,这个store就是最原始的经过createStore
建立的store,后两行只是变量赋值异步
var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) }; chain = middlewares.map(middleware => middleware(middlewareAPI)); dispatch = compose(...chain)(store.dispatch);
这里是关键,必须详细进行讲解。
首先,这边声明了一个middlewareAPI
对象,这个对象包含两个方法:
getState:store中的getState方法的引用
dispatch:对自己的dispatch方法进行一次封装
而后
chain = middlewares.map(middleware => middleware(middlewareAPI));
咱们来仔细看看这行代码,首先咱们对全部的中间件进行一个map,map结果就是调用中间件方法,将middlewareAPI
做为参数传入,
这里咱们拿redux-thunk
中间件举例,来看看一个中间件是长什么样子的,传入的参数又是用来干吗的。
export default function thunkMiddleware({ dispatch, getState }) { return next => action => typeof action === 'function' ? action(dispatch, getState) : next(action); }
redux-thunk
的功能是让action支持异步,让咱们能够在action中跟服务器进行交互等操做,而他的实现。。。(⊙﹏⊙)b是的,又是这么几行代码。
咱们回顾以前的代码,在map全部中间件的时候咱们调用了thunkMiddleware
方法,传入两个方法dispatch
和getState
,而后返回了一个方法,
咱们大体抽象一下,应该以下:
function (next) { return function (action) { typeof action === 'function' ? action(dispatch, getState) : next(action) } }
因而咱们接下去分析applyMiddleware
里面的代码,
chain = middlewares.map(middleware => middleware(middlewareAPI));
如今咱们知道chain是一个数组,每一项是调用每一个中间件以后的返回函数
dispatch = compose(...chain)(store.dispatch);
compose是redux里面的一个帮助函数,代码以下:
export default function compose(...funcs) { return arg => funcs.reduceRight((composed, f) => f(composed), arg); }
~~(>_<)~~我已经不想再吐槽什么了,
咱们看到这边先调用了compose
函数,传入告终构后的chain
数组,而后compose
函数返回的也是一个函数:
function (arg) { return funcs.reduceRight((composed, f) => f(composed), arg); // funcs就是中间件数组 }
而后咱们把store.dispatch
函数做为arg
传入这个结果,这里reduceRight能够参考这里
。那么这边获得的结果是什么呢?
// 假设中间件数组是[A, B, C] // 那么结果就是A(B(C(store.dispatch)))
再次结合redux-thunk
来看,咱们假设只有一个中间件,那么最终的dispatch
方法就是
function (action) { typeof action === 'function' ? action(dispatch, getState) : next(action) } // 这里的next方法,就是真正的store.dispatch方法 // 这里的dispatch是(action) => store.dispatch(action)
咱们再结合redux-thunk
的使用方法来分析一下,
function incrementAsync() { return dispatch => { setTimeout(() => { // Yay! Can invoke sync or async actions with `dispatch` dispatch(increment()); }, 1000); }; }
这是使用redux-thunk
时能够定义的异步action,咱们触发action的时候调用的是
dispatch(incrementAsync())
incrementAsync
返回的是
function (dispatch) { setTimeout(() => { // Yay! Can invoke sync or async actions with `dispatch` dispatch(increment()); }, 1000); }
这个时候咱们回想通过中间件加工的dispatch
方法:
function (action) { typeof action === 'function' ? action(dispatch, getState) : next(action) } // 这里的next方法,就是真正的store.dispatch方法 // 这里的dispatch是(action) => store.dispatch(action)
action是一个函数,因此action === 'function' ?
成立,那么就执行action, 并把中间件接收到的dispatch方法((action) => store.dispatch(action)
)方法做为参数传入,在异步方法执行完以后再次触发真正的action。若是action不是异步的,那么久直接返回一个对象,这个时候action === 'function' ?
不成立,就直接调用next
,也就是原始的store.dispatch
方法。
咱们再接着想,若是咱们有许多个中间件,那么没一个中间件的next
就是下一个中间件直到最后一个中间件调用store.dispatch
为止。
以上的代码很是绕,建议去专研一下源码。这么精简的代码包含了很是多的函数式编程的思想,也用到了装饰器模式的原理,不得不说:
太烧脑啦/(ㄒoㄒ)/~~