9

欢迎关注redux源码分析系列文章:
redux源码分析之一:createStore.js
redux源码分析之二:combineReducers.js
redux源码分析之三:bindActionCreators.js
redux源码分析之四:compose.js
redux源码分析之五:applyMiddleware

createStore.js是redux的核心文件,暴露了一个函数createStore,函数执行后返回一个对象,该对象包含了4个关键的方法:dispatch, subscribe, getState, replaceReducer,代码如下。

export default function createStore(reducer, preloadedState, enhancer) {
    //中间代码略
    return {
        dispatch,
        subscribe,
        getState,
        replaceReducer,
        [$$observable]: observable
      }
}

一、createStore函数的参数:

  1. reducer:reducer是一个函数,该函数会返回一个全新的state,而state则保存了所有的数据
  2. preloadedState:初始state
  3. enhancer:这个参数特别有意思,如果该enhancer参数存在的话,会将当前的createStore函数作为参数传入enhancer函数,并且,enhancer执行之后得到一个新函数,该新函数其实就是一个加强版的createStore函数,新的函数会把之前的reducer和preloadeState作为参数传入并执行。这个enhancer参数为redux中间件提供了入口。

二、参数检查代码及异常处理:

//如果preloadedState没有传,但是enhancer参数传了,重置一下变量
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined')          
  {
    enhancer = preloadedState
    preloadedState = undefined
  }
//如果enhancer传了,但是不是函数,则报错提示,否则执行enhancer函数,
//并继续执行enhancer函数返回的加强版的createStore函数,
//参数reducer以及preloadeState和原createStore函数保持一致
if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }
    return enhancer(createStore)(reducer, preloadedState)
  }
//如果reducer不是函数,则报错
if (typeof reducer !== 'function') {
    throw new Error('Expected the reducer to be a function.')
}

三、定义的几个局部变量:

let currentReducer = reducer //保存了当前的reducer函数,该reducer函数可以被动态替换掉
let currentState = preloadedState //保存了当前的state数据
let currentListeners = [] //保存了当前注册的函数列表
let nextListeners = currentListeners
let isDispatching = false  //是否正在dispatch一个action

最关键的是currentState变量,调用createStore之后,currentState变量保存了当前状态的所有数据

四、定义了几个函数:

//确保nextListeners和currentListeners不是同一个引用
function ensureCanMutateNextListeners() {
  if (nextListeners === currentListeners) {
    //如果是同一个引用,则浅拷贝currentListeners到nextListeners
    nextListeners = currentListeners.slice()
  }
}
//getState函数,返回局部变量currentState,以获取当前状态
function getState() {
  return currentState
}
  //注册一个函数,将注册函数放入局部变量nextListeners数组里面
  //注册函数的返回值是一个注销函数,注销函数执行可以将刚刚添加进nextListeners的listener函数又删除掉。这里很有意思,外部必须在调用subscribe执行现场保存好unsubscribe函数,否则将无法注销一个函数
  function subscribe(listener) {
    //如果listener不是函数,直接报错
    if (typeof listener !== 'function') {
      throw new Error('Expected listener to be a function.')
    }

    let isSubscribed = true
    //确保nextListeners不是currentListeners,以保证修改的是nextListeners,而不是currentListeners
    ensureCanMutateNextListeners()
    //将监听函数放入监听函数列表尾部
    nextListeners.push(listener)

    //返回一个函数,该函数可以从监听函数列表中删除刚刚注册的监听函数
    return function unsubscribe() {
      if (!isSubscribed) {
        return
      }

      isSubscribed = false

      ensureCanMutateNextListeners()
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)
    }
  }
  //触发action的函数:每次触发一个action,currentListeners中的所有函数都要执行一遍
  function dispatch(action) {
    //如果action不是普通的对象,直接报错
    if (!isPlainObject(action)) {
      throw new Error(
        'Actions must be plain objects. ' +
        'Use custom middleware for async actions.'
      )
    }
    //如果action没有type属性,直接报错:说明action对象必须要包含type字段
    if (typeof action.type === 'undefined') {
      throw new Error(
        'Actions may not have an undefined "type" property. ' +
        'Have you misspelled a constant?'
      )
    }
    //如果当前正在触发另外一个action,直接报错
    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions.')
    }

    try {
      //先将标志位置为true
      isDispatching = true
      //执行传入的reducer函数,该函数返回一个新的state对象,并赋值给currentState变量
      currentState = currentReducer(currentState, action)
    } finally {
      //reducer函数执行完成后,将isDispatching恢复成false,方便下次action的触发
      isDispatching = false
    }

    //每一次触发一个action,所有的监听函数都要全部重新执行一遍,
    //并且把上次得到的新的监听函数列表赋值成为当前的监听函数列表。这是一个懒操作,并不是在subscribe的时候就操作了,而是在dispatch的时候才操作
    const listeners = currentListeners = nextListeners
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }

    //该dispatch函数的返回值是原来的action
    return action
  }
  //替换reducer函数:这个函数允许运行时动态替换最开始调用createStore函数时传入的reducer,并且替换掉reducer之后,重新dispatch一个action,得到全新的currentState对象
  function replaceReducer(nextReducer) {
    //如果nextReducer不是函数,直接报错
    if (typeof nextReducer !== 'function') {
      throw new Error('Expected the nextReducer to be a function.')
    }
    //把新的reducer赋值给当前的currentReducer变量,得到一个全新的currentReducer
    currentReducer = nextReducer
    // 触发一个初始action:
    // 1.这样就可以完成一次监听函数列表的全部调用
    // 2.可以得到一个全新的currentState;
    dispatch({type: ActionTypes.INIT})
  }
function observable() {
    const outerSubscribe = subscribe
    return {
      /**
       * The minimal observable subscription method.
       * @param {Object} observer Any object that can be used as an observer.
       * The observer object should have a `next` method.
       * @returns {subscription} An object with an `unsubscribe` method that can
       * be used to unsubscribe the observable from the store, and prevent further
       * emission of values from the observable.
       */
      subscribe(observer) {
        if (typeof observer !== 'object') {
          throw new TypeError('Expected the observer to be an object.')
        }

        function observeState() {
          if (observer.next) {
            observer.next(getState())
          }
        }

        observeState()
        const unsubscribe = outerSubscribe(observeState)
        return {unsubscribe}
      },

      [$$observable]() {
        return this
      }
    }
  }

五、初始化:

初始化很简单,一句代码,直接调用一次dispatch,就会执行所有的注册函数,并且执行reducer函数,生成初始化的state

//马上内部调用一次初始化的操作,根据传入的reducer函数,preloadedState生成一个全新的currentState和全新的reducer
  dispatch({type: ActionTypes.INIT})

总结一下就是:

  1. createStore函数定义了几个局部变量用于记录状态,主要包括currentState记录数据状态,currentListeners记录注册函数列表,currentReducer记录当前的reducer函数。
  2. 定义了几个函数用于修改上面的几个局部变量:主要包括getState函数用于获取currentState;replaceReducer用于替换currentReducer;subscribe用于修改currentListeners列表;dispatch用于触发currentReducer执行,生成新的currentState,并且,执行currentListeners列表中的每一个函数;

完整解析请参考我的github:https://github.com/abczhijia/...,如果对您有帮助,欢迎star,有任何问题也请指正。

(完)


Happi
244 声望6 粉丝