redux源碼分析之一:createStore.js

歡迎關注redux源碼分析系列文章:
redux源碼分析之一:createStore.js
redux源碼分析之二:combineReducers.js
redux源碼分析之三:bindActionCreators.js
redux源碼分析之四:compose.js
redux源碼分析之五:applyMiddlewaregit

createStore.js是redux的核心文件,暴露了一個函數createStore,函數執行後返回一個對象,該對象包含了4個關鍵的方法:dispatch, subscribe, getState, replaceReducer,代碼以下。github

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

1、createStore函數的參數:

  1. reducer:reducer是一個函數,該函數會返回一個全新的state,而state則保存了全部的數據
  2. preloadedState:初始state
  3. enhancer:這個參數特別有意思,若是該enhancer參數存在的話,會將當前的createStore函數做爲參數傳入enhancer函數,而且,enhancer執行以後獲得一個新函數,該新函數其實就是一個增強版的createStore函數,新的函數會把以前的reducer和preloadeState做爲參數傳入並執行。這個enhancer參數爲redux中間件提供了入口。

2、參數檢查代碼及異常處理:

//若是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.')
}

3、定義的幾個局部變量:

let currentReducer = reducer //保存了當前的reducer函數,該reducer函數能夠被動態替換掉
let currentState = preloadedState //保存了當前的state數據
let currentListeners = [] //保存了當前註冊的函數列表
let nextListeners = currentListeners
let isDispatching = false  //是否正在dispatch一個action

最關鍵的是currentState變量,調用createStore以後,currentState變量保存了當前狀態的全部數據redux

4、定義了幾個函數:

//確保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
      }
    }
  }

5、初始化:

初始化很簡單,一句代碼,直接調用一次dispatch,就會執行全部的註冊函數,而且執行reducer函數,生成初始化的statesegmentfault

//立刻內部調用一次初始化的操做,根據傳入的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,有任何問題也請指正。app

(完)async

相關文章
相關標籤/搜索