粗读 Redux 源码

150 阅读7分钟

Redux

阅读 redux 源码

randomString 生成一个随机字符串

var randomString = function randomString() {
  return Math.random().toString(36).substring(7).split('').join('.');
};

Number.prototype.toString(): toString() 方法返回指定 Number 对象的字符串表示形式。

numObj.toString([radix])

  • 如果未指定radix参数,则默认值是10;
  • 如果radix参数不在2-36之间,将会抛出一个RangeError
  • 如果转换的基数大于10,则会使用字母来表示大于9的数字,比如基数为16的情况,则使用a到f的字母来表示10到15。
最近联想到的一个问题

[1, 2, 3, 2].map(parseInt) // [1, NaN, NaN, 2]

isPlainObject 判断是否是存粹的函数

function isPlainObject(obj) {
  if (typeof obj !== 'object' || obj === null) return false;
  var proto = obj;

  while (Object.getPrototypeOf(proto) !== null) {
    proto = Object.getPrototypeOf(proto);
  }

  return Object.getPrototypeOf(obj) === proto;
}

为什么写法要这么复杂?

  • obj 可能是从别的运行环境(比如浏览器中的同域iframe, nodejs中的vm)
  • 当然也有可能使这段代码表现出不同的结果
let obj = Object.create(Object.create(null));
// 写成字面量的话是这样的:
let obj = {
    __proto__: {
        __proto__: null
    }
};
isPlainObject(obj) // true
isPlainObject(null) // false

createStore 创建一颗Redux状态树 返回值是一个Store

  • reducer 是一个函数,接受当前state和要处理的action,返回一个新的state
  • preloadedState 初始化的state
  • enhancer Store增强器
function createStore(reducer, preloadedState, enhancer) {
  var _ref2;

  // 判断如果 preloadedState 是函数 并且 enhancer 是函数 或者 enhancer 和 第四个参数是函数的话 就抛出错误 只允许一个增强器 需要将增强器合并
  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.');
  }

  // 如果preloadedState 是函数 并且 enhancer 未传 则把函数当作增强器赋值给 enhancer 初始化状态赋值为 undefined
  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState;
    preloadedState = undefined;
  }

  // 经历过上面的操作 如果这时候增强器不为空 但是 不是函数 则抛出错误 
  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.');
    }

    // enhancer 不为空的时候 就开始增强store 增强器函数接受到的是 createStore 这个函数 返回值是一个函数 接受两个参数 reducer, preloadedState
    return enhancer(createStore)(reducer, preloadedState);
  }

  // 如果reducer 不是函数 能抛出错误 这里必须是个函数
  if (typeof reducer !== 'function') {
    throw new Error('Expected the reducer to be a function.');
  }

  // 当前reducer
  var currentReducer = reducer;
  // 当前state
  var currentState = preloadedState;
  // 当前监听器
  var currentListeners = [];
  var nextListeners = currentListeners;
  var isDispatching = false;

  // 实现一个currentListeners的浅复制
  function ensureCanMutateNextListeners() {
    if (nextListeners === currentListeners) {
      nextListeners = currentListeners.slice();
    }
  }

  // 获取当前应用的 state ,不能在 dispatch 的时候获取, 否则会报错
  function getState() {
    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;
  }

  // 增加一个 listener, 每次 dispatch 的时候都会被调用, 返回值是可以去关闭订阅的函数,直接调用即可 remove
  function subscribe(listener) {
    // 订阅函数必须是一个可以被调用的 函数
    if (typeof listener !== 'function') {
      throw new Error('Expected the listener to be a function.');
    }

    // 如果还是在 dispatch 中调用会抛出错误
    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;
    // 浅复制一下 currentListener 至 nextListeners
    ensureCanMutateNextListeners();
    // 然后把 新增的这个listener 加在刚刚浅复制出来的末尾
    nextListeners.push(listener);

    // 这个就是返回值 取消订阅
    return function unsubscribe() {
      // 如果已经被取消订阅 则直接 return
      if (!isSubscribed) {
        return;
      }

      //  如上一样 千万不要在 dispatch 的时候做任何操作
      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 的判断
      isSubscribed = false;
      // dispatch 的时候 会生成一个当前的快照
      ensureCanMutateNextListeners();
      var index = nextListeners.indexOf(listener);
      // 找出 然后删除
      nextListeners.splice(index, 1);

      // TODO: 然后把当前 currentListeners 清空
      currentListeners = null;
    };
  }

  // 更改 state 的唯一方式 action是没有副作用的对象(存粹) 返回传入的 action
  function dispatch(action) {
    // 判断 action 是否是存粹的 否则报错 需要用中间件处理
    if (!isPlainObject(action)) {
      throw new Error('Actions must be plain objects. ' + 'Use custom middleware for async actions.');
    }

    // 规定 action 必须要有 type 属性 而且不能是 undefined 
    if (typeof action.type === 'undefined') {
      throw new Error('Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?');
    }

    // reducer 中 不能dispatch 原因往后看
    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions.');
    }

    try {
      isDispatching = true;
      // currentReducer 也就是参数的reducer 接受两个参数 当前state currentState 也可能是 undefined
      currentState = currentReducer(currentState, action);
    } finally {
      // 当 reducer 执行完成 isDispatching 变成 false
      isDispatching = false;
    }

    // 这里会跟上面联动 就是 unsubscribe 的时候要再次浅拷贝一下 每一次执行完之后 都会又一个最新的 listener 的快照
    var listeners = currentListeners = nextListeners;

    for (var i = 0; i < listeners.length; i++) {
      var listener = listeners[i];
      listener();
    }

    return action;
  }
  
  // 更换 reducer 并且改变 state 返回 空
  function replaceReducer(nextReducer) {
    //  还是一样 如果 reducer 不是函数就报错
    if (typeof nextReducer !== 'function') {
      throw new Error('Expected the nextReducer to be a function.');
    }

    currentReducer = nextReducer;

    // 发起一个 replace 的 action
    dispatch({
      type: ActionTypes.REPLACE
    });
  }
  

  function observable() {
    var _ref;

    // 上面定义的 subscribe 函数 接收一个 listener 作为参数 返回一个去掉当前 listener 的函数
    var outerSubscribe = subscribe;
    return _ref = {
      // 一个 subscribe 函数 接收的参数是 一个 具有 next 属性的对象 返回的是一个具有 unsubscribede 的对象
      subscribe: function subscribe(observer) {
        // 如果 observer 不是对象报错 
        if (typeof observer !== 'object' || observer === null) {
          throw new TypeError('Expected the observer to be an object.');
        }

        // https://github.com/tc39/proposal-observable
        function observeState() {
          if (observer.next) {
            // 会传入当前的 state
            observer.next(getState());
          }
        }

        // 初始化一次
        observeState();
        // 注册 observeState listener 
        var unsubscribe = outerSubscribe(observeState);
        return {
          unsubscribe: unsubscribe
        };
      }
    }, _ref[$$observable] = function () {
      // TODO
      return this;
    }, _ref; // 这里是一个 逗号 表达式 最终返回的是 _ref
  } 

  // 当创建一个 store 的时候 通过reducer创建初始化state
  dispatch({
    type: ActionTypes.INIT
  });

  //  同上 返回的是 _ref2 store 对象 包括一个dispatch / subscribe / getState / replaceReducer 还有个 observable 的属性
  return _ref2 = {
    dispatch: dispatch,
    subscribe: subscribe,
    getState: getState,
    replaceReducer: replaceReducer
  }, _ref2[$$observable] = observable, _ref2;
}

warning 在 console 中打印出警告的信息

  function warning(message) {
    // 一个好的习惯 在调用之前判断 console 是否存在 适用于不同的上下文
    if (typeof console !== 'undefined' && typeof console.error === 'function') {
      console.error(message);
    }

    try {
      throw new Error(message);
    } catch (e) {} 

  }

getUndefinedStateErrorMessage 当 reducer 通过 action 返回undefined 的时候的错误提示信息

function getUndefinedStateErrorMessage(key, action) {
  var actionType = action && action.type;
  var actionDescription = actionType && "action \"" + String(actionType) + "\"" || 'an action';
  return "Given " + actionDescription + ", reducer \"" + key + "\" returned undefined. " + "To ignore an action, you must explicitly return the previous state. " + "If you want this reducer to hold no value, you can return null instead of undefined.";
}

getUnexpectedStateShapeWarningMessage 通过对比 state 和 reducer 的属性 发出警告

function getUnexpectedStateShapeWarningMessage(inputState, reducers, action, unexpectedKeyCache) {
  var reducerKeys = Object.keys(reducers);
  var argumentName = action && action.type === ActionTypes.INIT ? 'preloadedState argument passed to createStore' : 'previous state received by the reducer';

  // 不能没有 reducer,否则报错
  if (reducerKeys.length === 0) {
    return 'Store does not have a valid reducer. Make sure the argument passed ' + 'to combineReducers is an object whose values are reducers.';
  }

  // 如果不是存粹的 state 也是要报错
  if (!isPlainObject(inputState)) {
    return "The " + argumentName + " has unexpected type of \"" + {}.toString.call(inputState).match(/\s([a-z|A-Z]+)/)[1] + "\". Expected argument to be an object with the following " + ("keys: \"" + reducerKeys.join('", "') + "\"");
  }

  var unexpectedKeys = Object.keys(inputState).filter(function (key) {
    return !reducers.hasOwnProperty(key) && !unexpectedKeyCache[key];
  });
  unexpectedKeys.forEach(function (key) {
    unexpectedKeyCache[key] = true;
  });
  // REPLACE 除外
  if (action && action.type === ActionTypes.REPLACE) return;

  // 不然必须要 每个 state 的属性 存在对应的 reducer
  if (unexpectedKeys.length > 0) {
    return "Unexpected " + (unexpectedKeys.length > 1 ? 'keys' : 'key') + " " + ("\"" + unexpectedKeys.join('", "') + "\" found in " + argumentName + ". ") + "Expected to find one of the known reducer keys instead: " + ("\"" + reducerKeys.join('", "') + "\". Unexpected keys will be ignored.");
  }
}

assertReducerShape 判断 reducers 是否都是合法的

function assertReducerShape(reducers) {
  Object.keys(reducers).forEach(function (key) {
    var reducer = reducers[key];
    var initialState = reducer(undefined, {
      type: ActionTypes.INIT
    });

    // 如果初始化时候 或者 state 给 undefined 的时候 要返回初始化的 state 否则报错
    if (typeof initialState === 'undefined') {
      throw new Error("Reducer \"" + key + "\" returned undefined during initialization. " + "If the state passed to the reducer is undefined, you must " + "explicitly return the initial state. The initial state may " + "not be undefined. If you don't want to set a value for this reducer, " + "you can use null instead of undefined.");
    }

    // 要能接的住一个 未知的 action 有个 default 返回当前的state 否则会报错
    if (typeof reducer(undefined, {
      type: ActionTypes.PROBE_UNKNOWN_ACTION()
    }) === 'undefined') {
      throw new Error("Reducer \"" + key + "\" returned undefined when probed with a random type. " + ("Don't try to handle " + ActionTypes.INIT + " or other actions in \"redux/*\" ") + "namespace. They are considered private. Instead, you must return the " + "current state for any unknown actions, unless it is undefined, " + "in which case you must return the initial state, regardless of the " + "action type. The initial state may not be undefined, but can be null.");
    }
  });
}

combineReducers 整合 reducers 变成一个单一的reducer / 返回值是一个函数 接收初始化 state,接收一个 action 返回更改过后的 state

function combineReducers(reducers) {
  var reducerKeys = Object.keys(reducers);
  var finalReducers = {};

  // 遍历整个 reducer
  for (var i = 0; i < reducerKeys.length; i++) {
    var key = reducerKeys[i];

    if (process.env.NODE_ENV !== 'production') {
      //  如果不是生产环境 就会在控制台 打印警告信息
      if (typeof reducers[key] === 'undefined') {
        warning("No reducer provided for key \"" + key + "\"");
      }
    }

    // 通过判断是否是函数 最终的 reducers 形成 也可以去重 防止传入的 reducers 是有重复 key
    if (typeof reducers[key] === 'function') {
      finalReducers[key] = reducers[key];
    }
  }

  var finalReducerKeys = Object.keys(finalReducers); 

  var unexpectedKeyCache;

  if (process.env.NODE_ENV !== 'production') {
    unexpectedKeyCache = {};
  }

  var shapeAssertionError;

  try {
    // 判断 reducers 是否合法
    assertReducerShape(finalReducers);
  } catch (e) {
    shapeAssertionError = e;
  }

  // 返回值是一个函数 接收一个state 以及 action
  return function combination(state, action) {
    // 如果 state 未传 则给一个空对象
    if (state === void 0) {
      state = {};
    }

    // 上面的错误 如果发现有 reducer 不符合规范 就抛出错误
    if (shapeAssertionError) {
      throw shapeAssertionError;
    }

    if (process.env.NODE_ENV !== 'production') {
      // 如果不是生产环境 检查传入的 state 是否有key 没有对应的 reducer 
      var warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache);

      if (warningMessage) {
        warning(warningMessage);
      }
    }

    var hasChanged = false;
    var nextState = {};

    // 遍历最终的 reducers
    for (var _i = 0; _i < finalReducerKeys.length; _i++) {
      var _key = finalReducerKeys[_i];
      var reducer = finalReducers[_key];
      var previousStateForKey = state[_key];
      // previousStateForKey 可能是 undefined 所以 reducer 必须要有一个默认 state 
      var nextStateForKey = reducer(previousStateForKey, action);

      if (typeof nextStateForKey === 'undefined') {
        // 如果没有给默认的state 就报错
        var errorMessage = getUndefinedStateErrorMessage(_key, action);
        throw new Error(errorMessage);
      }

      nextState[_key] = nextStateForKey;
      // 通过对比 state 有没有变化
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
    }

    hasChanged = hasChanged || finalReducerKeys.length !== Object.keys(state).length;
    // 如果 reducer 改变了 state 里面的值 或者 reducer 和 state 值对不上 则返回最新的 state => nextState
    return hasChanged ? nextState : state;
  };
}

bindActionCreator 接收一个 actionCreator 函数 第二个参数是 dispatch

function bindActionCreator(actionCreator, dispatch) {
  // 返回一个函数 dispatch 一个 action
  return function () {
    return dispatch(actionCreator.apply(this, arguments));
  };
}

bindActionCreators 第一个参数 可以是function 或者是 值是 actionCreator 的对象 第二个参数是 dispatch 返回值是用dispatch的函数 或者 以其为值的 对象

function bindActionCreators(actionCreators, dispatch) {
  // 如果 第一个参数 是函数 则直接返回被 dispatch 包裹的函数
  if (typeof actionCreators === 'function') {
    return bindActionCreator(actionCreators, dispatch);
  }

  // 如果不是对象 排除到 null 的情况 则抛出错误
  if (typeof actionCreators !== 'object' || actionCreators === null) {
    throw new Error("bindActionCreators expected an object or a function, instead received " + (actionCreators === null ? 'null' : typeof actionCreators) + ". " + "Did you write \"import ActionCreators from\" instead of \"import * as ActionCreators from\"?");
  }

  var boundActionCreators = {};

  for (var key in actionCreators) {
    //  hasOwnProperty
    var actionCreator = actionCreators[key];

    if (typeof actionCreator === 'function') {
      boundActionCreators[key] = bindActionCreator(actionCreator, dispatch);
    }
  }

  // 返回值 就是每个都用 dispatch 包裹的 函数 看上一个函数
  return boundActionCreators;
}

_defineProperty Object.defineProperty 的函数

function _defineProperty(obj, key, value) {
  if (key in obj) {
    Object.defineProperty(obj, key, {
      value: value,
      enumerable: true,
      configurable: true,
      writable: true
    });
  } else {
    obj[key] = value;
  }

  return obj;
}

ownKeys 接收一个参数 和 一个是否可以枚举的参数 返回所有的 key

function ownKeys(object, enumerableOnly) {
  // 对象上所有的 key 但是不包括 symbol 的 key
  var keys = Object.keys(object);

  // 加上 Symbol 的 key
  if (Object.getOwnPropertySymbols) {
    keys.push.apply(keys, Object.getOwnPropertySymbols(object));
  }

  if (enumerableOnly) keys = keys.filter(function (sym) {
    // 访问器属性
    return Object.getOwnPropertyDescriptor(object, sym).enumerable;
  });
  return keys;
}

_objectSpread2

function _objectSpread2(target) {
  // 遍历参数 如果都没有 直接返回 
  for (var i = 1; i < arguments.length; i++) {
    // 不能是 null 因为不能对 null 或者 undefined 使用 Object.getOwnPropertyDescriptors
    var source = arguments[i] != null ? arguments[i] : {};

    // 遍历所有参数 整合成一个 Object
    if (i % 2) {
      ownKeys(source, true).forEach(function (key) {
        _defineProperty(target, key, source[key]);
      });
    } else if (Object.getOwnPropertyDescriptors) {
      Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
    } else {
      ownKeys(source).forEach(function (key) {
        Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
      });
    }
  }

  return target;
}

compose 柯里化 (...args) => f(g(h(...args))) 从右向左依次执行

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];
  }

  // 一个 reduce 函数 从左到右 依次包裹 最后面的 在最里面
  return funcs.reduce(function (a, b) {
    return function () {
      return a(b.apply(void 0, arguments));
    };
  });
}

applyMiddleware 接收一些中间件 生成一个完整的增强器

function applyMiddleware() {
  // 同上 转成中间件的数组
  for (var _len = arguments.length, middlewares = new Array(_len), _key = 0; _key < _len; _key++) {
    middlewares[_key] = arguments[_key];
  }

  // 返回一个函数 接收的参数 是 createStore
  return function (createStore) {
    return function () {

      // 生成一个 store
      var store = createStore.apply(void 0, arguments);

      // 不能在构建 middleware 的时候 dispatch 因为如果调用的话 其余中间件 也不会收到这个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.');
      };

      // 先传入一个能够报错的 dispatch 防止在构建 middleware 过程中 调用 dispatch
      var middlewareAPI = {
        getState: store.getState,
        dispatch: function dispatch() {
          return _dispatch.apply(void 0, arguments);
        }
      };

      // 生成一个 middleware 的 数组
      var chain = middlewares.map(function (middleware) {
        return middleware(middlewareAPI);
      });
      // 生成一个增强的 dispatch chain中 中间件 接收一个 {getState, dispatch} 返回一个函数接收一个dispatch 的函数
        = compose.apply(void 0, chain)(store.dispatch);
      // 生成一个增强过的 store 对象
      return _objectSpread2({}, store, {
        dispatch: _dispatch
      });
    };
  };
}

isCrushed 假函数

function isCrushed() {}

// 如果不是生产环境 但是函数名字被压缩过了 就告警
if (process.env.NODE_ENV !== 'production' && typeof isCrushed.name === 'string' && isCrushed.name !== 'isCrushed') {
  warning('You are currently using minified code outside of NODE_ENV === "production". ' + 'This means that you are running a slower development build of Redux. ' + 'You can use loose-envify (https://github.com/zertosh/loose-envify) for browserify ' + 'or setting mode to production in webpack (https://webpack.js.org/concepts/mode/) ' + 'to ensure you have the correct code for your production build.');
}

以上就是全部 redux 代码

下面结合例子再次巩固

import { createStore, applyMiddleware, combineReducers, compose } from 'redux';
import reducers from './reducers';

// 假定有两个中间件
import thunk from 'redux-thunk';

// https://github.com/fcomb/redux-logger.git
const logMiddleware = ({ getState }) => dispatch => {
  return action => {
    const current prevState = getState()
    const returnValue = dispatch(action)
    const nextValue = getState()


    if (typeof console !== 'undefined') {
      const message = `action ${action.type} @ ${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}`;

      try {
        console.group(message);
      } catch(e) {
        console.log('NOT GROUP');
      }

      console.log(`%c prev state`, `color: #9E9E9E; font-weight: bold`, prevState);
      console.log(`%c action`, `color: #03A9F4; font-weight: bold`, action);
      console.log(`%c next state`, `color: #4CAF50; font-weight: bold`, nextState);

      try {
        console.groupEnd('—— log end ——');
      } catch(e) {
        console.log('—— log end ——');
      }
    }
    // 返回值若不变 能就是 action
    return returnValue;
  }
}

// 生成中间件集合
const createStoreWithMiddleware = applyMiddleware(logger, thunk)(createStore);
// 生成 reducer
const reducer = combineReducers(reducers);
// 然后生成的全局 store
const store = createStoreWithMiddleware(reducer);