JavaScript 須要管理比任什麼時候候都要多的 state (狀態)編程
state 在何時,因爲什麼緣由,如何變化已然不受控制。redux
經過限制更新發生的時間和方式,Redux 試圖讓 state 的變化變得可預測。設計模式
action => middleware => reducer(s) => Store閉包
這是redux提供的幾個關鍵文件和它們的做用,其實簡單他們提供的功能不難發現他們函數式編程的影子。redux裏面設計比較巧妙的點我的感受是在中間件裏。middleware在redux中被設計爲在action發起後,到達reducer以前的拓展點。咱們能夠利用middleware實現相似日誌記錄,錯誤定位或者路由,還有異步處理action這些操做。app
redux的源碼是比較典型的FP風格,掌握一些基本FP概念,再去閱讀redux源碼會輕鬆不少異步
Higher order functions can take functions as parameters and return functions as return values.函數式編程
接受函數做爲參數傳入,並能返回封裝後函數。函數
Currying > Currying is the technique of translating the evaluation of a function that takes multiple arguments into evaluating a sequence of functions, each with a single argument學習
是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,而且返回接受餘下的參數並且返回結果的新函數的技術。 add(1,2,3) => add(1)(2)(3)this
Compose > Composes functions from right to left. 組合函數,將從右向左執行。
compose(subtract,multiple,add)(200) 等同於 subtract(multiple(add(200)));
內部使用reduce,而不是直接嵌套。
store.dispatch(action) => middleware =>reducer => store
貼上實現單向數據流的關鍵源碼(部分刪減)
dispatch函數的實現 (/createStore.js)
每次咱們調用原生dispatch時,都會有這樣的流程,在上圖第五行裏dispatch函數將拿到的action交給reducer函數處理,這裏的isDispatching
變量用來控制在reducer函數執行過程當中不容許再次dispatch,這個過程用try/finally提供可靠性;第十行取得當前監聽器函數列表的快照,在for循環中依次執行,這裏執行也是有講究,並無直接
listener[i]()
調用,而是採用了分割this的行爲逐個調用監聽器函數。總結這個dispatch函數關鍵點以下
combineReducer函數的實現(/combineReducers.js)
中間件發揮做用的時間點在派發action後,達到reducer前,能夠理解爲在調用原生dispatch(action)前,使用了中間件。 與其按照時間節點來理解,倒不如說中間件是爲了加強dispatch函數而作的設計 applyMiddleware的源碼很是精煉
帶着問題來閱讀源碼,中間件是如何實現如下幾點功能的這裏聲明瞭一個middlewareAPI,經過裏面的getState方法就能夠拿到store裏的數據,另一個dispatch並無什麼實際的做用,就算調用了,它也會告訴你不能使用,這裏利用map將middlewareAPI傳入到每一箇中間件裏,構造了一個閉包,讓中間件能夠訪問到state數據,這裏也利用了currying函數延遲執行的特性,它接受了參數執行可是返回的是另一個待執行的函數。 如此就保證了每一箇中間件能夠獲取到state,關鍵點在於中間件科裏化的設計,讓其能夠延遲執行和參數複用。
const middlewareAPI = { getState: store.getState, dispatch: (...args) => dispatch(...args) }
// 利用currying函數延遲執行的特性
複製代碼
如何將中間件串聯起來,並保存最後一個函數傳入的參數爲store.dispatch 想實現這個特性就要用到compose組合函數, 將中間件串聯起來,而且最後一個函數入參爲store.dispatch, 傳入的next就是下一個中間件,固然最後一個函數接受的next就是原生的store.dispatch,那個時候中間件就處理完畢,將action派發到reducer了。
const a = next => action => next(action)
const b = next => action => next(action)
const c = dispatch => action => dispatch(action)
compose(c, b, a)(store.dispatch)
// 源碼實現 dispatch = compose(...chain)(store.dispatch)
複製代碼
函數簽名middleware = store => next => action => { next(action) }
其實看到這裏應該也大體明白了爲何要這麼設計中間件,返回的第一個函數是爲了保證中間件能夠取到全局狀態,返回的第二個函數是爲了保證中間件能夠依次調用。redux裏的中間件是一個科裏化的函數,其主要目的是爲了利用其延遲計算和參數複用的能力,來實現中間件的衆多特性。
redux雖然爲咱們解決了state的管理問題,但依然不是百分之百的完美。邏輯上redux提供了一套簡單可行且很是清晰規範的state管理方案,數據的單數據流和其三個原則,與之帶來的是會寫一些模板代碼,若是使用了中間件,特別是redux-saga那種獨立規範特別多的中間件,會耗費咱們不少的時間在寫模板上,雖然咱們能夠對數據流動掌控的特別精細,可是時間成本依然減緩了咱們開發的效率。
redux的改進應該在保留優點設計,解決痛點的基礎上進行。其實在多數開發者使用redux時通常會對其作簡單的封裝再使用,對redux增長一些設計模式或是使用企業內部的diapatch加強方法,這裏拋磚引玉,提出幾個redux理想改進的幾個須要注意的地方