嗯,就是学习一下,读读源码。顺便把源码里的文档翻译了一下并添加了一些简单的注释。

本文对应的文件是src/createStore.js

import isPlainObject from 'lodash/isPlainObject'
import $$observable from 'symbol-observable'

/**
 * ActionTypes里定义的是Redux保留的私有action。
 * 对于任何未知的action,你必须返回store的当前状态。
 * 如果传入的当前状态是undefined,你必须返回store的初始状态。
 * 不要在应用代码中直接引用这些action。
 */
export var ActionTypes = {
  INIT: '@@redux/INIT'
}

/**
 * createStore方法用于创建一个保存程序状态的store。
 * 改变store中数据的唯一方法是调用store的`dispatch()`方法。
 *
 * 你的应用中应该只有一个store。为了将程序状态中不同部分的变更逻辑
 * 组合在一起,你可以通过`combineReducers`方法将多个reducer组合成一个reducer。
 *
 * @param {Function} reducer 一个返回应用下一状态的函数,入参是程序的当前状态以及
 * 要发送的action。
 *
 * @param {any} [preloadedState] store的初始状态。你可以选择性的为store指定一个
 * 初始状态。
 * 如果你使用了`combineReducers`方法来生成最终的reducer。那么这个初始状态对象的
 * 结构必须与调用`combineReducers`方法时传入的参数的结构保持对应关系。
 *
 * @param {Function} enhancer store增强器。你可以选择性的传入一个增强函数来扩展
 * store的功能,例如中间件,时间旅行,持久化等。Redux自带的唯一一个增强器是
 * `applyMiddleware()`方法。
 *
 * @returns {Store} 返回一个可以读取状态,发送action以及订阅变更通知的Redux store。
 */
export default function createStore(reducer, preloadedState, enhancer) {
  // 如果只传入reducer和enhancer,则store的初始状态为undefined
  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState
    preloadedState = undefined
  }

  // enhancer必须是一个函数
  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }

    // 返回使用enhancer增强后的store
    return enhancer(createStore)(reducer, preloadedState)
  }


  // reducer必须是一个函数
  if (typeof reducer !== 'function') {
    throw new Error('Expected the reducer to be a function.')
  }

  var currentReducer = reducer
  var currentState = preloadedState
  var currentListeners = []
  var nextListeners = currentListeners
  var isDispatching = false

  // 在每次修改监听函数数组之前复制一份,实际的修改发生在这个新
  // 复制出来的数组上。确保在某次dispatch发生前就存在的监听器,
  // 在该次dispatch之后都能被触发一次。
  function ensureCanMutateNextListeners() {
    if (nextListeners === currentListeners) {
      nextListeners = currentListeners.slice()
    }
  }

  /**
   * 读取store状态
   *
   * @returns {any} 返回store的当前状态
   */
  function getState() {
    return currentState
  }

  /**
   *
   * 新增一个变更监听函数。每当dispatch了一个action之后监听函数都会被触发一次。
   * 你可以在监听函数中通过`getState()`方法获取store的最新状态。
   *
   * 你可以在一个回调函数中再次调用`dispatch()`。但需要注意以下两点:
   *
   * 1. 在每一次dispatch()调用执行之前,监听函数数组都会被复制一份(通过前文提到
   * 的ensureCanMutateNextListeners方法)。如果你在监听函数中增加或删除其他监听函
   * 数,那么这些操作并不会影响到当前进行中的这一轮dispatch。而下一次dispatch,
   * 不论其是否是嵌套调用,都会使用最新的,修改后的监听函数列表。
   *
   * 2. 由于在一个监听函数执行前可能已经进行了多次嵌套的dispatch调用,因此不能保证
   * 每个监听函数都可以获取到所有的状态变更。然而,可以确定的是,在某次dispatch
   * 触发之前已经注册的监听函数都可以读取到这次diapatch之后store的最新状态。
   *
   * @param {Function} listener 每次dispatch之后执行的回调函数
   * @returns {Function} 返回一个用于取消这次订阅的函数
   */
  function subscribe(listener) {
    if (typeof listener !== 'function') {
      throw new Error('Expected listener to be a function.')
    }

    var isSubscribed = true

    // 添加监听函数前确保只操作当前数组的一份拷贝
    ensureCanMutateNextListeners()
    nextListeners.push(listener)

    return function unsubscribe() {
      if (!isSubscribed) {
        return
      }

      isSubscribed = false

      // 移除监听函数前确保只操作当前数组的一份拷贝
      ensureCanMutateNextListeners()
      var index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)
    }
  }

  /**
   * 发送一个action。这是触发状态变更的唯一方法。
   *
   * 每次发送action的时候,用于创建store的`reducer`函数都会被调用一次。调用时
   * 传入的参数是当前的状态以及被发送的`action`。调用的返回值会被当做更新后的
   * 状态。调用完成后,所有的状态监听函数都会被触发。
   *
   * 基础实现中仅支持发送形式为简单对象的action。如果你希望可以发送Promise,Observable,
   * thunk或是其它形式的action,你需要使用相应的中间件把store创建函数封装起来。
   * 你可以在`redux-thunk`模块的文档中找到这方面的示例。不过即使在这些中间件内部
   * 还是通过dispatch方法发送了简单对象形式的action。
   *
   * @param {Object} action 一个表示变更内容的对象。保证你的action是可被序列化的
   * 是一种很好的实践,这样你就可以记录并回放用户的操作,或是使用可以穿梭时间
   * 的`redux-devtools`插件。一个action必须有一个值不为`undefined`的`type`属性。
   * 推荐你使用字符串常量来表示action类型。
   *
   * @returns {Object} 为了方便起见,返回你传入的action对象。
   *
   * 要注意的是,如果你使用了一个自定义的中间件,它可能会把`dispatch()`的返回值
   * 封装成其它内容(比如,一个你可以await的Promise)
   */
  function dispatch(action) {
    // 如果action不是简单对象,抛出异常
    if (!isPlainObject(action)) {
      throw new Error(
        'Actions must be plain objects. ' +
        'Use custom middleware for async actions.'
      )
    }

    // 如果action的类型是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.')
    }

    // 执行reducer,传入当前状态和action
    try {
      isDispatching = true
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }

    // 触发所有的状态监听回调函数
    var listeners = currentListeners = nextListeners
    for (var i = 0; i < listeners.length; i++) {
      listeners[i]()
    }

    return action
  }

  /**
   * 替换store当前使用的reducer函数
   * 
   * 如果你的应用程序实现了代码拆分并且你希望动态加载某些reducer的时候你
   * 可能会用到这个方法。或者当你要为Redux实现一个热加载机制的时候,你也
   * 会用到它。
   *
   * @param {Function} nextReducer 要使用的新reducer
   *
   * @returns {void}
   */
  function replaceReducer(nextReducer) {
    if (typeof nextReducer !== 'function') {
      throw new Error('Expected the nextReducer to be a function.')
    }

    currentReducer = nextReducer
    dispatch({ type: ActionTypes.INIT })
  }

  /**
   * 为observable/reactive库预留的交互接口。
   * @returns {observable} 表示状态变更的最简单的observable对象
   * 想要获取更多信息,可以查看observable提案:
   * https://github.com/zenparsing/es-observable
   */
  function observable() {
    // 首先保留对Redux中subscribe方法的引用,在observable的世界里
    // 有一个同名方法。
    var outerSubscribe = subscribe
    return {
      /**
       * 一个极简的observable订阅方法。
       * @param {Object} observer 任何可以作为observer使用的对象
       * observer对象应该包含一个`next`方法。
       * @returns {subscription} 返回一个带有`unsbscribe`方法的对象。该
       * 方法将用于停止接收来自store的状态变更信息。
       */
      subscribe(observer) {
        // observer参数必须是一个对象,否则抛出异常。但并未检测是否有next方法。。。
        if (typeof observer !== 'object') {
          throw new TypeError('Expected the observer to be an object.')
        }

        // 创建一个状态变更回调函数。逻辑很简单,把store最新的状态传给observer
        function observeState() {
          if (observer.next) {
            observer.next(getState())
          }
        }

        // 立即执行一次回调函数,把当前状态传给observer
        observeState()
        var unsubscribe = outerSubscribe(observeState)
        return { unsubscribe }
      },
      // 根据observable提案,[Symbol.observable]()返回observable对象自身
      [$$observable]() {
        return this
      }
    }
  }

  // store创建好以后,立即发送一个初始化action。这样做是为了让reducer
  // 返回store的初始状态(当给reducer传入的当前state为undefined时,reducer
  // 会返回store的初始状态)。

  dispatch({ type: ActionTypes.INIT })

  // 返回创建好的store对象
  return {
    dispatch,
    subscribe,
    getState,
    replaceReducer,
    [$$observable]: observable
  }
}