歡迎關注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 } }
//若是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變量保存了當前狀態的全部數據redux
//確保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函數,生成初始化的statesegmentfault
//立刻內部調用一次初始化的操做,根據傳入的reducer函數,preloadedState生成一個全新的currentState和全新的reducer dispatch({type: ActionTypes.INIT})
總結一下就是:數組
完整解析請參考個人github:https://github.com/abczhijia/...,若是對您有幫助,歡迎star,有任何問題也請指正。app
(完)async