一句話總結
Middleware就是增強了dispatch
開始呼叫createStore發生了什麼
//呼叫
const store = createStore(rootReducer, applyMiddleware(...middlewares));
//createStore
export default function createStore(reducer, preloadedState, enhancer)
//如果第二個引數是function,並且沒傳第三個引數,則將第二個引數賦值給第三個引數,然後將第二個引數設為undefined
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState
preloadedState = undefined
}
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
//返回一個高階函式
return enhancer(createStore)(reducer, preloadedState)
}
}
複製程式碼
通過呼叫createStore 返回的結果可以解析為
applyMiddleware(...middlewares)(createStore)(reducer, initialState)
複製程式碼
applyMiddleware原始碼裡發生了什麼
//呼叫applyMiddleware,可以傳入多箇中介軟體
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, initialState, enhancer) => {
var store = createStore(reducer, initialState, enhancer)
var dispatch = store.dispatch
var chain = []
//將state和dispatch所指向的函式繫結到middlewareAPI
var middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
}
//迭代中介軟體陣列,並執行一遍,將middlewareAPI作為最外層的store,並返回一個相當於next函式的陣列
chain = middlewares.map(middleware => middleware(middlewareAPI))
//將陣列整理成巢狀的函式體,並將store.dispatch傳入最內側的函式的next,並返回經過處理的dispatch
//dispatch是一個函式,是一個巢狀了多層的函式,其最裡面呼叫的是store.dispatch
dispatch = compose(...chain)(store.dispatch)
//返回一個新的store
return {
...store,
dispatch
}
}
}
複製程式碼
大致看下,其實就是通過一些操作,然後返回一個經過處理的store,dispatch
具體做了些什麼
var middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
複製程式碼
- 定義了一個物件(middlewareAPI) ,並將 store.state和store.dispatch繫結到這個物件中(都是引用)
- 然後迴圈這些中介軟體,並將middlewareAPI作為引數執行middleware,因為都是高階函式,所以返回的是next陣列,並儲存到chain中
- 最重要的是下一步的compose函式
export default function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
複製程式碼
這裡有必要解釋下funcs.reduce((a, b) => (...args) => a(b(...args))) 這一坨做了些什麼?
reduce 是專門為累加操作設計的,啥意思呢
先把funcs.reduce((a, b) => (...args) => a(b(...args))) 翻譯一下
- 假如說 funcs[a,b,c,d,e,f]
- 那麼執行之後的結果就是a(b(c(d(e(f(...args)))
- 因為是compose(...chain)(store.dispatch)呼叫,所以...args就是store.dispatch,原生的dispatch,就是說最內層,呼叫的是原生的dispatch
- 這個有個洋蔥模型,網上覆制一個
所以最後返回的dispatch是經過處理的dispatch:a(b(c(d(e(f(store.dispatch)))
解釋下chain是什麼?
//以redux-saga為例
//看引數,就知道為什麼定義middlewareAPI物件了
function sagaMiddleware({ getState, dispatch }) {
...
return next => action => {
if (sagaMonitor && sagaMonitor.actionDispatched) {
sagaMonitor.actionDispatched(action)
}
const result = next(action) // hit reducers
channel.put(action)
return result
}
}
複製程式碼
- 從原始碼上可以分析出當執行chain = middlewares.map(middleware => middleware(middlewareAPI))時 直接返回了next()函式
- 當有一堆middleware時,執行middleware都返回一個next()函式
- 所以chain就是一個next()陣列
- 而這個next()其實就是下一個middleware
- 一直next到最裡面的執行store.dispatch
流程
- 呼叫applyMiddleware傳入n個 middleware
- 用 middlewareAPI 儲存了當前的store.state,store.dispatch(每個middleware共享)
- 迭代middlewares,執行每個middleware並攜帶middlewareAPI,返回一個next()
- 將chain整理成巢狀的函式,最裡層呼叫store.dispatch
- 返回一個經過處理的dispatch
用一個最噁心的方式總結
//模擬三個middleware
function A(next){
return function A1(action){
next(action)
}
}
function B(next){
return function B1(action){
next(action)
}
}
function C(next){
return function C1(action){
next(action)
}
}
複製程式碼
假設 dispatch = A(B(C(store.dispatch))),開始執行
function A1(action){
function B1(action){
return function C1(action){
store.dispatch(action)
}
}
}(action)
複製程式碼
一個action的執行順序:A(action) -> B(action) -> C(action) -> store.dispatch(action),先從內到外生成新的func,然後由外向內執行.