學(xué)習(xí)過react的同學(xué)肯定都用過redux。了解redux數(shù)據(jù)流機(jī)制的action->dispatch->store->reduce->頁面交互其實(shí)很好理解劲赠,可是當(dāng)我們要用到異步請(qǐng)求或者打印日志之類的副操作的時(shí)候,我們無法避免的會(huì)用到中間件Middleware秸谢。中間件都是怎么執(zhí)行以及如何有序的串在一起很令人迷惑经磅,下面我將嘗試解釋這個(gè)過程:
演變過程
假如你有個(gè)需求需要在分發(fā)dispatch前后打印不同狀態(tài)值,你肯定會(huì)這么想:
console.log('dispatching', action)
store.dispatch(action)
console.log('next state', store.getState())
封裝成函數(shù):
function dispatchAndLog(store, action) {
console.log('dispatching', action)
store.dispatch(action)
console.log('next state', store.getState())
}
//執(zhí)行
dispatchAndLog(store, action)
不妨改造store的dispatch更為直接些:
let next = store.dispatch
store.dispatch = function dispatchAndLog(action) {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
Redux把這個(gè)封裝的入口寫成了一個(gè)函數(shù)钮追,就叫applyMiddleware预厌。由此我們明白了applyMiddleware的功能:改造dispatch函數(shù),產(chǎn)生真假dispatch元媚,而中間件就是運(yùn)行在假真(dispatchAndLog假和next真)之間的代碼轧叽。
這里我們要對(duì)applyMiddleware進(jìn)行一個(gè)準(zhǔn)確的定義苗沧,它只是一個(gè)用來加工dispatch的工廠,而要加工什么樣的dispatch出來炭晒,則需要我們傳入對(duì)應(yīng)的中間件函數(shù)(比如上例中的dispatchAndLog)待逞,下面我們構(gòu)造一個(gè)精簡(jiǎn)版的applyMiddleware:
function applyMiddleware(middleware){
let next = store.dispatch;
store.dispatch = middleware(store)(next); // 這里傳入store,是因?yàn)橹虚g件中有可能會(huì)用到getState獲取數(shù)據(jù)网严,比如打印當(dāng)前用戶等需求
}
}
applyMiddleware(dispatchAndLog)
中間串連
中間件的功能各不相同识樱,它們都要融入到dispatch中,在派發(fā)action的時(shí)候震束,按照順序一個(gè)個(gè)的執(zhí)行怜庸,這是一個(gè)費(fèi)腦經(jīng)的事情。在上例中middleware會(huì)返回新的dispatch垢村,我們需要做的也就是將產(chǎn)生的新的dispatch傳遞個(gè)下個(gè)中間件即可割疾。如下:
function applyMiddleware(middleware,middleware2){
let next = store.dispatch;
store.dispatch = middleware2(middleware(store)(next));
// 這里傳入store嘉栓,是因?yàn)橹虚g件中有可能會(huì)用到getState獲取數(shù)據(jù)宏榕,比如打印當(dāng)前用戶等需求
}
}
applyMiddleware(dispatchAndLog,dispatchmethed)
以此類推有大量的中間件的時(shí)候我們可以這么干:
function applyMiddleware(...middlewares){
middlewares = middlewares.slice();
middlewares.reverse(); //執(zhí)行順序是后到前侵佃,所以得倒置
let dispatch = store.dispatch
//循環(huán)嵌套
middlewares.foreach(function(middleware){
dispatch = middleware(store)(dispatch);
});
return Object.assign({}, store, { dispatch }); //合并dispatch到redux里麻昼。
}
請(qǐng)注意這里是一個(gè)循環(huán)嵌套的一個(gè)過程,所以中間的順序決定著中間件的執(zhí)行順序馋辈。
總結(jié)兩點(diǎn):
- 中間件在執(zhí)行完副操作會(huì)并會(huì)返回新的dispatch
- applyMiddleware本質(zhì)是一個(gè)循環(huán)嵌套調(diào)用的過程涌献。