說說面試官:說說對Redux中間件的理解?常用的中間件有哪些?實現原理?
一、是什么
中間件(Middleware)在計算機中,是介于應用系統和系統軟件之間的一類軟件,它使用系統軟件所提供的基礎服務(功能),銜接網絡上應用系統的各個部分或不同的應用,能夠達到資源共享、功能共享的目的
在這篇文章中,了解到了Redux整個工作流程,當action發出之后,reducer立即算出state,整個過程是一個同步的操作
那么如果需要支持異步操作,或者支持錯誤處理、日志監控,這個過程就可以用上中間件
Redux中,中間件就是放在就是在dispatch過程,在分發action進行攔截處理,如下圖:
其本質上一個函數,對store.dispatch方法進行了改造,在發出 Action和執行 Reducer這兩步之間,添加了其他功能
二、常用的中間件
有很多優秀的redux中間件,這里我們例舉兩個:
- redux-thunk:用于異步操作
- redux-logger:用于日志記錄
上述的中間件都需要通過applyMiddlewares進行注冊,作用是將所有的中間件組成一個數組,依次執行
然后作為第二個參數傳入到createStore中
- const store = createStore(
- reducer,
- applyMiddleware(thunk, logger)
- );
redux-thunk
redux-thunk是官網推薦的異步處理中間件
默認情況下的dispatch(action),action需要是一個JavaScript的對象
redux-thunk中間件會判斷你當前傳進來的數據類型,如果是一個函數,將會給函數傳入參數值(dispatch,getState)
dispatch函數用于我們之后再次派發action
getState函數考慮到我們之后的一些操作需要依賴原來的狀態,用于讓我們可以獲取之前的一些狀態
所以dispatch可以寫成下述函數的形式:
- const getHomeMultidataAction = () => {
- return (dispatch) => {
- axios.get("http://xxx.xx.xx.xx/test").then(res => {
- const data = res.data.data;
- dispatch(changeBannersAction(data.banner.list));
- dispatch(changeRecommendsAction(data.recommend.list));
- })
- }
- }
redux-logger
如果想要實現一個日志功能,則可以使用現成的redux-logger
- import { applyMiddleware, createStore } from 'redux';
- import createLogger from 'redux-logger';
- const logger = createLogger();
- const store = createStore(
- reducer,
- applyMiddleware(logger)
- );
這樣我們就能簡單通過中間件函數實現日志記錄的信息
三、實現原理
首先看看applyMiddlewares的源碼
- export default function applyMiddleware(...middlewares) {
- return (createStore) => (reducer, preloadedState, enhancer) => {
- var store = createStore(reducer, preloadedState, enhancer);
- 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}
- }
- }
所有中間件被放進了一個數組chain,然后嵌套執行,最后執行store.dispatch??梢钥吹剑虚g件內部(middlewareAPI)可以拿到getState和dispatch這兩個方法
在上面的學習中,我們了解到了redux-thunk的基本使用
內部會將dispatch進行一個判斷,然后執行對應操作,原理如下:
- function patchThunk(store) {
- let next = store.dispatch;
- function dispatchAndThunk(action) {
- if (typeof action === "function") {
- action(store.dispatch, store.getState);
- } else {
- next(action);
- }
- }
- store.dispatch = dispatchAndThunk;
- }
實現一個日志輸出的原理也非常簡單,如下:
- let next = store.dispatch;
- function dispatchAndLog(action) {
- console.log("dispatching:", addAction(10));
- next(addAction(5));
- console.log("新的state:", store.getState());
- }
- store.dispatch = dispatchAndLog;
參考文獻
http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_two_async_operations.html
http://cn.redux.js.org/