zoukankan      html  css  js  c++  java
  • 浅谈redux 中间件的原理

    在使用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"));

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

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

  • 相关阅读:
    ASP.NET在访问Controller的方法带参数时怎样防止黑客攻击
    ASP.NET项目在VS中F5与Ctrl+F5的区别
    ASP.NET中MVC添加Controller以及访问其Action
    ASP.NET中MVC编程模式简介与搭建HelloWorld项目
    搭建自己的博客(三十):添加修改密码,忘记密码
    pycharm破解
    安装更新npm和nodejs
    搭建自己的博客(二十九):增加绑定邮箱的功能,完善用户信息
    格式化注释
    搭建自己的博客(二十八):自定义用户模型
  • 原文地址:https://www.cnblogs.com/JhoneLee/p/5771541.html
Copyright © 2011-2022 走看看