Skip to content

Redux 源码解析 #13

@wlsyne

Description

@wlsyne

Redux 源码解析

所有的解析都是结合源码的,我会以注释的形式写上自己的理解
文章中的源码,因为和整体理解 redux 的流程无关,有些部分我删除掉了(比如报错啊这些)

redux 的用法

//我随便找了个我的项目中使用的redux
import { createStore, applyMiddleware, compose } from 'redux';
import rootReducer from './rootReducer';
import createSagaMiddleware from 'redux-saga';
import rootSaga from './rootSaga';
const sagaMiddleware = createSagaMiddleware();

const middlewares = [sagaMiddleware];

if (process.env.NODE_ENV === 'development') {
  const { createLogger } = require('redux-logger');

  const logger = createLogger({ collapsed: true });
  middlewares.push(logger);
}

export default function configureStore(initialState) {
  const store = createStore(
    rootReducer,
    initialState,
    compose(applyMiddleware(...middlewares)),
  );
  sagaMiddleware.run(function* () {
    yield rootSaga();
  });
  if (module.hot) {
    module.hot.accept('./rootReducer', () => {
      const nextRootReducer = require('./rootReducer').default;
      store.replaceReducer(nextRootReducer);
    });
  }
  return store;
}

combineReducers

//reducers我们一般的写法就是个对象,value就是一个reducer函数
function combineReducers(reducers) {
  //获取所有reducer的key
  var reducerKeys = Object.keys(reducers);
  //存储过滤后的reducer
  var finalReducers = {};

  for (var i = 0; i < reducerKeys.length; i++) {
    var key = reducerKeys[i];
    //将非函数的reducer过滤
    if (typeof reducers[key] === 'function') {
      finalReducers[key] = reducers[key];
    }
  }
  //获取过滤后的key
  var finalReducerKeys = Object.keys(finalReducers);
  //返回一个函数接受一个原state和一个action
  return function combination(state, action) {
    //判断state是否为undefined
    if (state === void 0) {
      state = {};
    }
    //state经过计算对比后是否改变
    var hasChanged = false;
    //计算过后的新的state
    var nextState = {};
    //循环执行所有的reducer
    for (var _i = 0; _i < finalReducerKeys.length; _i++) {
      var _key = finalReducerKeys[_i];
      var reducer = finalReducers[_key];
      //之前的局部state
      var previousStateForKey = state[_key];
      //计算过后的局部state
      var nextStateForKey = reducer(previousStateForKey, action);
      nextState[_key] = nextStateForKey;
      //比较之前的局部state和计算过后的局部state是否相等
      //这里可以看出是直接比较两个对象
      //如果在原来的对象上修改state那么对象的指针没有改变,无论你怎么改state中的数据都是相等的
      //这就是reducer中必须返回一个新的对象的原因
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
    }
    //根据hasChanged结果判断返回旧的state还是新的state
    hasChanged =
      hasChanged || finalReducerKeys.length !== Object.keys(state).length;
    return hasChanged ? nextState : state;
  };
}

compose

然后我们来看下这段代码

const store = createStore(
  rootReducer,
  initialState,
  compose(applyMiddleware(...middlewares)),
);

分析下 compose 函数

我们先从最里面来分析解读,那么就从 compose 入手吧
我们先通过下面这段代码看看 compose 做了什么

let funcs = [f1, f2, f3];

funcs.reduce((preValue, fn) => {
  return (...args) => {
    return preValue(fn(...args));
  };
});

//第一次循环的时候reduce函数没有指定initialValue,那么第一次循环会跳过
//第二次循环的时候preValue就会是f1(如果对reduce这个api不熟悉可以去看下文档)
let loop2ReturnVal = (...args) => {
  return f1(f2(...args));
};
//第三次循环
let loop3ReturnVal = (...args) => {
  return loop2ReturnVal(f3(...args));
};
//将loop2ReturnVal带入执行
let loop3ReturnVal = (...args) => {
  return f1(f2(f3(...args)));
};
//所以compose的作用就是实现函数的嵌套调用
//将传入的函数从右边到左边依次调用

redux 中 compose 的源码

function compose() {
  for (
    var _len = arguments.length, funcs = new Array(_len), _key = 0;
    _key < _len;
    _key++
  ) {
    funcs[_key] = arguments[_key];
  }
  if (funcs.length === 0) {
    return function (arg) {
      return arg;
    };
  }
  if (funcs.length === 1) {
    return funcs[0];
  }
  return funcs.reduce(function (a, b) {
    return function () {
      return a(b.apply(void 0, arguments));
    };
  });
}

我相信根据上面的分析你已经知道了 compose 是来做什么的
那么我们来分析下上面的 compose 返回了什么

compose(applyMiddleware(...middlewares))
//由上面的源码我们可以看出,compose只传入一个函数返回的是函数本身
//感觉compose没起到什么作用,我们传入两个函数试试
compose(applyMiddleware(...middlewares),(f)=>{return f})
//这个函数最终返回的是
function(...args){
	return applyMiddleware(...middlewares)((f)=>{return f}(...args))
}
//那第二个函数为什么要接收一个参数并且要把这个参数返回出去呢?
//我们可以在createStore这个函数的源码中找到答案

CreateStore:第一部分

createStore 我们分两部分来看
现在先分析第一部分

function createStore(reducer, preloadedState, enhancer) {
  var _ref2;
  //下面这两个判断传参的问题
  //一般第二个preloadedState我们都没有传
  //enhancer的位置一般就传的compose函数
  if (
    (typeof preloadedState === 'function' && typeof enhancer === 'function') ||
    (typeof enhancer === 'function' && typeof arguments[3] === 'function')
  ) {
    throw new Error(
      'It looks like you are passing several store enhancers to ' +
        'createStore(). This is not supported. Instead, compose them ' +
        'together to a single function.',
    );
  }

  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState;
    preloadedState = undefined;
  }
  //可以看出是先给enhancer函数传入一个createStore并执行
  //然后再给enhancer函数执行后的返回值传入reducer、preloadedState这两个参数并执行
  if (typeof enhancer !== 'undefined') {
    //给enhancer传入一个createStore参数
    return enhancer(createStore)(reducer, preloadedState);
  }
  ........
  //这一部分的代码主要是定义了一些方法,我们在下一部分解析
  ........
  //最后return出去了一个_ref2对象
  //里面有dispatch、subscribe、getState、replaceReducer、$$observable这些方法
  return (
    (_ref2 = {
      dispatch: dispatch,
      subscribe: subscribe,
      getState: getState,
      replaceReducer: replaceReducer,
    }),
    (_ref2[$$observable] = observable),
    _ref2
  );
}

根据上面我们的分析

//enhancer函数
function(...args){
	return applyMiddleware(...middlewares)((f)=>{return f}(...args))
}

//可以看到(f)=>{return f}这个函数相当于直接传递了createStore
//这是因为applyMiddleware需要接收createStore(下面我们会讲到)
//那么enhancer(createStore)的执行结果就是
applyMiddleware(...middlewares)(createStore)

//enhancer(createStore)(reducer, preloadedState)的结果就是
applyMiddleware(...middlewares)(createStore)(reducer,preloadedState)

applyMiddleware

function applyMiddleware() {
  //获取传入的中间件
  //比如说这里我们传入的是saga
  //createSagaMiddleware()
  for (
    var _len = arguments.length, middlewares = new Array(_len), _key = 0;
    _key < _len;
    _key++
  ) {
    middlewares[_key] = arguments[_key];
  }
  //这里是个函数的curry化
  //可以看到这个地方接收一个createStore然后返回一个参数
  return function (createStore) {
    return function () {
      var store = createStore.apply(void 0, arguments);

      var _dispatch = function dispatch() {
        throw new Error(
          'Dispatching while constructing your middleware is not allowed. ' +
            'Other middleware would not be applied to this dispatch.',
        );
      };

      var middlewareAPI = {
        getState: store.getState,
        dispatch: function dispatch() {
          return _dispatch.apply(void 0, arguments);
        },
      };
      var chain = middlewares.map(function (middleware) {
        return middleware(middlewareAPI);
      });
      _dispatch = compose.apply(void 0, chain)(store.dispatch);
      // _objectSpread2对象展开符的polyfill
      return _objectSpread2({}, store, {
        dispatch: _dispatch,
      });
    };
  };
}

那么接下来我们带入这段代码中执行

// applyMiddleware(...middlewares)(createStore)(reducer,preloadedState)

//相当于执行下面的函数
function () {
  		//创建了一个store
  		//返回值就是上面说到的
  		/*{
       *  dispatch: dispatch,
       *  subscribe: subscribe,
       *  getState: getState,
       *  replaceReducer: replaceReducer
			 *  $$observable: observable
       *}
      */
      var store = createStore.apply(void 0, arguments);
			//创建了一个dispatch函数
      var _dispatch = function dispatch() {
        throw new Error('Dispatching while constructing your middleware is not allowed. ' + 'Other middleware would not be applied to this dispatch.');
      };

      var middlewareAPI = {
        getState: store.getState,
        dispatch: function dispatch() {
          return _dispatch.apply(void 0, arguments);
        }
      };
  		//将上面的middlewareAPI为参数传入middleware中执行
  		//我们结合一下saga的源码看一下
      var chain = middlewares.map(function (middleware) {
        return middleware(middlewareAPI);
      });
  		//经过下面的saga分析
  		//我们可以得出
			//chain就变成了,因为下面要用到compose,所以我加了一个函数,让compose的结果看起来更加直观
  		chain=[function (next) {
      				return function (action) {
        				if (sagaMonitor && sagaMonitor.actionDispatched) {
          					sagaMonitor.actionDispatched(action);
        				}
        				var result = next(action); // hit reducers
        				sagaEmitter.emit(action);
        				return result;
                };
              },
             function(next){
               return function(action){
                 	// ...
                  // 中间件处理逻辑
                  // ...
               		return next(action)
               }
             }
            ]
  		//上面那个chain是我为了看起来方便,实际上源码里面并没有哈

  		//compose功能跟上面相同,从右到左依次执行函数
      _dispatch = compose.apply(void 0, chain)(store.dispatch);
  		//最后返回一个有被中间件扩展功能后的dispatch的store
      return _objectSpread2({}, store, {
        dispatch: _dispatch
      });
  		//这下我们可以得出一个结论,中间件其实是丰富了dispatch的功能
  		//每次dispatch一个action,都会经过中间件的层层处理
  		//而且可以初略的对洋葱模型有个认识
  		//compose的时候是从里到外绑定中间件
  		//执行的时候是从外到里执行
  		//这里有点绕 可以自己理一下体会一下,我也想了老半天
    }(reducer,preloadedState)

saga 中间件的创建函数

//代码中是这样使用的
const sagaMiddleware = createSagaMiddleware();
//createSagaMiddleware的源码
function sagaMiddlewareFactory() {
  //返回来了一个函数
  //接收一个_ref2参数
  //也就是上面的middlewareAPI
  function sagaMiddleware(_ref2) {
    var getState = _ref2.getState,
      dispatch = _ref2.dispatch;
    ....
    //中间是saga中间件的一堆逻辑
    ....

    //getState和dispatch都没有在返回的函数中用到,只是在中间件自己的处理逻辑中用到
    return function (next) {
      return function (action) {
        if (sagaMonitor && sagaMonitor.actionDispatched) {
          sagaMonitor.actionDispatched(action);
        }
        var result = next(action); // hit reducers
        sagaEmitter.emit(action);
        return result;
      };
    };
  }
  return sagaMiddleware;
}

CreateStore:第二部分

function createStore(reducer, preloadedState, enhancer) {
  ......
  var currentReducer = reducer;
  var currentState = preloadedState;
  var currentListeners = [];
  var nextListeners = currentListeners;
  var isDispatching = false;

  //这是个工具函数
  //用来判断currentListeners和nextListeners的指针是否一样,如果一样,那么就复制一个新的nextListeners
  function ensureCanMutateNextListeners() {
    if (nextListeners === currentListeners) {
      nextListeners = currentListeners.slice();
    }
  }

  //获取当前的state
  function getState() {
    //如果是dispatching状态的话就抛出错误
    if (isDispatching) {
      throw new Error(
        'You may not call store.getState() while the reducer is executing. ' +
          'The reducer has already received the state as an argument. ' +
          'Pass it down from the top reducer instead of reading it from the store.',
      );
    }
    return currentState;
  }

  function subscribe(listener) {
    //判断listener是不是个函数
    if (typeof listener !== 'function') {
      throw new Error('Expected the listener to be a function.');
    }
    //判断是否是在dispatching状态
    if (isDispatching) {
      throw new Error(
        'You may not call store.subscribe() while the reducer is executing. ' +
          'If you would like to be notified after the store has been updated, subscribe from a ' +
          'component and invoke store.getState() in the callback to access the latest state. ' +
          'See https://redux.js.org/api-reference/store#subscribelistener for more details.',
      );
    }

    var isSubscribed = true;
    ensureCanMutateNextListeners();
    nextListeners.push(listener);
    //返回一个解除监听的函数
    return function unsubscribe() {
      if (!isSubscribed) {
        return;
      }

      if (isDispatching) {
        throw new Error(
          'You may not unsubscribe from a store listener while the reducer is executing. ' +
            'See https://redux.js.org/api-reference/store#subscribelistener for more details.',
        );
      }

      isSubscribed = false;
      ensureCanMutateNextListeners();
      var index = nextListeners.indexOf(listener);
      nextListeners.splice(index, 1);
      currentListeners = null;
    };
  }

  function dispatch(action) {
    //判断action的值
    if (!isPlainObject(action)) {
      throw new Error(
        'Actions must be plain objects. ' +
          'Use custom middleware for async actions.',
      );
    }

    if (typeof action.type === 'undefined') {
      throw new Error(
        'Actions may not have an undefined "type" property. ' +
          'Have you misspelled a constant?',
      );
    }

    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions.');
    }
    //更新state
    try {
      isDispatching = true;
      currentState = currentReducer(currentState, action);
    } finally {
      isDispatching = false;
    }

    var listeners = (currentListeners = nextListeners);
    //循环执行监听函数
    for (var i = 0; i < listeners.length; i++) {
      var listener = listeners[i];
      listener();
    }

    return action;
  }

  //替换reducer
  function replaceReducer(nextReducer) {
    if (typeof nextReducer !== 'function') {
      throw new Error('Expected the nextReducer to be a function.');
    }

    currentReducer = nextReducer;

    dispatch({
      type: ActionTypes.REPLACE,
    });
  }

  //用于初始化state,因为这个action都会直接命中reducer中的default分支
  dispatch({
    type: ActionTypes.INIT,
  });
  return (
    (_ref2 = {
      dispatch: dispatch,
      subscribe: subscribe,
      getState: getState,
      replaceReducer: replaceReducer,
    }),
    (_ref2[$$observable] = observable),
    _ref2
  );
}

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions