博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
浅谈redux 中间件的原理
阅读量:4552 次
发布时间:2019-06-08

本文共 4550 字,大约阅读时间需要 15 分钟。

在使用redux管理异步数据流的时候,我们会使用中间件,以redux-thunk中间件为例,我们做一下分析:

首先是构建store,我们需要以下代码进行揉入中间件的类似creatStore函数的构造:

const loggerMiddleware = createLogger();const createStoreWithMiddleware = applyMiddleware(  thunkMiddleware,  loggerMiddleware)(createStore);export default function configureStore(initialState) {    return createStoreWithMiddleware(rootReducer, initialState);}

在这段代码中,我们用到了 

applyMiddleware 函数去将中间件揉入构造store的工厂函数中,
applyMiddleware函数的源码如下所示:
import compose from './compose'export default function applyMiddleware(...middlewares) {  return (createStore) => (reducer, initialState, enhancer) => {    var store = createStore(reducer, initialState, 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    }  }}
先看函数的return,我们通过applyMiddleware构建得到的createStoreWithMiddleware函数其实是这样一个函数
function (reducer, initialState, enhancer){      .......      return {          ...store,          dispatch     }}

而store就是它return出来的这个对象

 

store的建立流程大致就是这样,但此时store的dispatch方法已经不是原来的dispatch,注意下面的代码:

chain = middlewares.map(middleware => middleware(middlewareAPI))dispatch = compose(...chain)(store.dispatch)

这才是 applyMiddleware 方法的核心,它将每个middleware进行处理,并存入到chain 的数组中,然后调用compose方法对chain数组进行处理,处理出来的返回值就是store的dispatch,也就是我们在业务代码中用到的dispatch

接下来看一下compose方法做了什么:

export default function compose(...funcs) {  if (funcs.length === 0) {    return arg => arg  } else {    const last = funcs[funcs.length - 1]    const rest = funcs.slice(0, -1)    return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args))  }}

它通过调用数组的reduceRight方法对各个中间件进行整合

reduceRight方法的 第一参数是 callback(preValue,curValue) ,第二个参数是要传递给callback作为第一个参数preValue来使用的

这时我们回到applyMiddleware方法中的这段代码:

var middlewareAPI = {      getState: store.getState,      dispatch: (action) => dispatch(action)    }    chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch)

由此我们可以知道传给last(...args)的正是 store.dispatch

我们根据官方文档可以知道中间件的通用构造如下:(箭头函数这里略过)

function middleware({dispatch, getState}) {    return function (next) {        return function (action) {            return next(action);        }    }}

chain数组里面的数据结构是这样的 :[ function(next){return function(action){...}},function(next){return function(action){...}} ...]

也就是 middleware函数的里面一层 的这个函数

function (next) {        return function (action) {            return next(action);        }    }

然后再经过compose的进一步reduceRight提炼:

return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args))

compose就是 function(action){return next(action)}

在经过 f(composed) 仍是   function(action){return next(action);} 只不过这里的next是上一个中间件的返回值,追溯源头,next其实就是 store.dispatch一路经过f(composed)这种方式将中间件的方法揉和进来的变种dispatch

所以经过揉入中间件的createStore工厂函数返回的store对象的dispatch方法,其实就是function(action){return next(action);}

然后结合实际中我们使用redux-thunk进行异步数据操作,thunk源码如下:

function createThunkMiddleware(extraArgument) {  return ({ dispatch, getState }) => next => action => {    if (typeof action === 'function') {      return action(dispatch, getState, extraArgument);    }    return next(action);  };}const thunk = createThunkMiddleware();thunk.withExtraArgument = createThunkMiddleware;export default thunk;//箭头函数转变正常就是这样function createThunkMiddleware(extraArgument) {  return function({ dispatch, getState }){       return  function(next){             return function(action){               if (typeof action === 'function') {                 return action(dispatch, getState, extraArgument);               }               return next(action);            }     }  };}

通过上面分析,我们的store.dispatch就是这个东西

function(action){               if (typeof action === 'function') {                 return action(dispatch, getState, extraArgument);               }               return next(action);            }

我们在调用异步获取数据的时候 action是这样写的:

export function fetchUri(key){    return function(dispatch){        dispatch(request("show"));        return $.ajax({            url:BOOKLIST_REQ.uri,            dataType:"jsonp",            data:{q:key,count:BOOKLIST_REQ.count}        }).done(res=>{            dispatch(receive(res));            dispatch(request("hidden"));        }).fail(res=>console.error(res));    };}

激发调取异步数据方法是  store.dispatch(fetchUrl("xxx"));

这样后面的就不用细说了,怎么执行下来就一目了然了吧

这就是整个中间件大致的工作过程,如果有什么说的不对的地方,你特么来打我呀!

 

转载于:https://www.cnblogs.com/JhoneLee/p/5771541.html

你可能感兴趣的文章
os模块
查看>>
Windows下启动停止Oracle11g服务-为解决系统变慢而生
查看>>
基于Spring Security Oauth2的SSO单点登录+JWT权限控制实践
查看>>
null与undefind的区别(转)
查看>>
Web前端的状态管理(State Management)
查看>>
EF|CodeFirst数据并发管理
查看>>
[Java] Spring boot2 整合 Thymeleaf 后 去除模板缓存
查看>>
java并发:阻塞队列
查看>>
[NOI2001] 炮兵阵地 (状压Dp经典例题)
查看>>
Selenium三种等待元素的方式及代码,需要特别注意implicitlyWait的用法
查看>>
sublime Text2下安装php code sniffer插件
查看>>
在Emacs中使用plantuml画UML图
查看>>
[启动]Linux启动流程rcN.d rcS.d rc.local等
查看>>
Resouse of Buddhism
查看>>
Android实用代码七段(三)
查看>>
打造一个壁纸爬虫来爬你的老婆
查看>>
mysql 给用户设置权限
查看>>
K-Means算法总结
查看>>
TrunCateTable 和Delete Table 的区别
查看>>
Mybatis <where>标签
查看>>