在研究 redux-saga時(shí),發(fā)現(xiàn)自己對(duì) redux middleware 不是太了解,因此,便決定先深入解讀一下 redux 源碼。跟大多數(shù)人一樣,發(fā)現(xiàn) redux源碼 真的很精簡(jiǎn),目錄結(jié)構(gòu)如下:
|—— utils
|—— warnings.js
|—— applyMiddleware.js
|—— bindActionCreator.js
|—— combineReducers.js
|—— compose.js
|—— createStore.js
|—— index.js
在 index.js 中導(dǎo)出了5個(gè)模塊,即外部可用的:
export {
createStore,
combineReducers,
bindActionCreators,
applyMiddleware,
compose
}
然而,當(dāng)真正解讀的時(shí)候,發(fā)現(xiàn)還真是有點(diǎn)吃不消,經(jīng)過(guò)幾天的硬啃之后,只能說(shuō):終于等到你,還好我沒(méi)放棄。。。(自帶BGM)
這里,我可能不會(huì)仔細(xì)去分析它的源碼,但會(huì)就自己的理解進(jìn)行梳理概括,具體的對(duì)我很有幫助的文章會(huì)放到結(jié)尾參考處。
首先是對(duì) createStore 、 applyMiddleware 及 compose 的梳理,因?yàn)檫@3個(gè)模塊存在相互調(diào)用的關(guān)系,其關(guān)系圖如下(高清圖請(qǐng)查看 redux源碼圖解之createStore和applyMiddleware):

1. 每個(gè)模塊的作用
createStore 的函數(shù)的作用就是生成一個(gè) store 對(duì)象,這個(gè)對(duì)象具有5個(gè)方法:
return {
dispatch, // 傳入 action,調(diào)用 reducer 及觸發(fā) subscribe 綁定的監(jiān)聽函數(shù)
subscribe,
getState,
replaceReducer, // 用新的 reducer 代替當(dāng)前的 reducer,使用不多
[$$observable]: observable
}
而 applyMiddleware 函數(shù)的作用就是對(duì) store.dispatch 方法進(jìn)行增強(qiáng)和改造,使得在發(fā)出 Action 和執(zhí)行 Reducer 之間添加其他功能。
compose 函數(shù)則是 applyMiddleware 函數(shù)的核心,其會(huì)形成串聯(lián)的函數(shù)調(diào)用關(guān)系,用于增強(qiáng) dispatch 方法。
2. 模塊之間的調(diào)用關(guān)系
(i) 首先,createStore 模塊會(huì)對(duì)傳入的參數(shù)進(jìn)行判斷,分別處理不同參數(shù)的情況,當(dāng)傳入 applyMiddleware(...middleware) 的時(shí)候,就會(huì)返回 applyMiddleware(...middleware) 執(zhí)行之后的高階函數(shù),即:
// createStore.js
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
// 這里的 enhancer 是 applyMiddleware(...) 執(zhí)行后的高階函數(shù),傳參無(wú) enhancer
return enhancer(createStore)(reducer, preloadedState)
}
(ii)然后,就進(jìn)入了 applyMiddleware 模塊內(nèi)部的邏輯,從 createStore 返回的高階函數(shù),其傳入的參數(shù)是沒(méi)有 enhancer 的,因此走的是 createStore 函數(shù)中沒(méi)有傳入 enhancer 的邏輯,用于先獲得沒(méi)有中間件時(shí)返回的 store。
// applyMiddleware.js
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState, enhancer) => {
const store = createStore(reducer, preloadedState, enhancer)
let dispatch = store.dispatch
let chain = [] // 用于存放獲取了store的中間件數(shù)組
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
(iii)接著,獲取最原始的 store 的 getState 和 dispatch,封裝于 middlewareAPI 對(duì)象。將該對(duì)象傳入中間件 middleware 中,形成中間件數(shù)組 chain。
其中,middleware 的范式是:(store) => (next) => (action) => {},將 middlewareAPI 傳入middleware 后,中間件便獲得了 {getState, dispacth}。至此,chain 中間件數(shù)組中包含的每個(gè)中間件的形式都變成了 (next) => (action) => {} 的形式。
(iiii)最后,調(diào)用 compose 函數(shù),如 chian = [middleware1, middleware2, middleware3],則 dispatch = compose(...chain)(store.dispatch),即執(zhí)行 middleware1(middleware2(middleware3(store.dispatch))),然后賦值給 dispatch。
總之,不管是否有
applyMiddleware,createStore的結(jié)果都是輸出一個(gè) store 對(duì)象,而applyMiddleware則可以對(duì) store 對(duì)象中的dispatch進(jìn)行改造。