成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Redux 中間件分析

littlelightss / 2296人閱讀

摘要:假設(shè)等于,其中,,是三個(gè)中間件,等于,那么可以簡化為。最終返回中的方法以及經(jīng)過中間件包裝處理過的方法。以此類推,第二個(gè)返回的就是第一個(gè)中間件的形參。根據(jù)這個(gè)的討論,在中間件頂層調(diào)用了,結(jié)果導(dǎo)致無法執(zhí)行后面的中間件。

redux 主要包含 5 個(gè)方法,分別是:

createStore

combineReducers

bindActionCreators

applyMiddleware

compose

今天主要講解下 applyMiddlewarecompose 這兩個(gè)方法。在 redux 中引入了中間件的概念,沒錯(cuò)如果你使用過 Express 或者 Koa 的話,一定不會(huì)對中間件陌生。我們知道,在 Koa 中,串聯(lián)各個(gè)中間件的正是 compose 方法,所以在 redux 中也同樣使用了這個(gè)命名,作用也是串聯(lián)所有中間件。

reduce 用法

在正式講解前,我們先來看下 reduce 的用法。根據(jù) MDN 上的解釋,

reduce() 方法是對累加器和數(shù)組中的每個(gè)元素(從左到右)應(yīng)用一個(gè)函數(shù),將其減少為單個(gè)值。
arr.reduce(callback[, initialValue])
參數(shù)

callback

執(zhí)行數(shù)組中每個(gè)值的函數(shù),包含四個(gè)參數(shù):

accumulator:累加器累加回調(diào)的返回值; 它是上一次調(diào)用回調(diào)時(shí)返回的累積值,或 initialValue

currentValue:數(shù)組中正在處理的元素。

currentIndex:數(shù)組中正在處理的當(dāng)前元素的索引。 如果提供了initialValue,則索引號(hào)為0,否則為索引為1。

array:調(diào)用 reduce 的數(shù)組

initialValue

用作第一個(gè)調(diào)用 callback的第一個(gè)參數(shù)的值。 如果沒有提供初始值,則將使用數(shù)組中的第一個(gè)元素。 在沒有初始值的空數(shù)組上調(diào)用 reduce 將報(bào)錯(cuò)。

返回

函數(shù)累計(jì)處理的結(jié)果

compose 分析

有了上面 reduce 的基礎(chǔ),我們再來看下 compose 的代碼。compose 的代碼很簡單,10行代碼左右,但你看到 reduce 部分的時(shí)候,估計(jì)會(huì)一臉懵逼,短短的一行代碼看上去卻很繞。

/**
 * Composes single-argument functions from right to left. The rightmost
 * function can take multiple arguments as it provides the signature for
 * the resulting composite function.
 *
 * @param {...Function} funcs The functions to compose.
 * @returns {Function} A function obtained by composing the argument functions
 * from right to left. For example, compose(f, g, h) is identical to doing
 * (...args) => f(g(h(...args))).
 */
 
export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

看注釋,它的作用應(yīng)該是

執(zhí)行 compose(f, g, h)
得到 (...args) => f(g(h(...args)))

我們來推導(dǎo)下,它是怎么得出這個(gè)結(jié)果的。假設(shè) funcs 等于 [f1, f2, f3],其中 f1f2,f3 是三個(gè)中間件,(a, b) => (..args) => a(b(...args)) 等于 f,那么 funcs.reduce((a, b) => (...args) => a(b(...args))) 可以簡化為 [f1, f2, f3].reduce(f)。

第 1 次執(zhí)行 f

a = f1
b = f2 
返回 (...args) => f1(f2(..args))

第 2 次執(zhí)行 f

a = (...args) => f1(f2(...args))
b = f3
返回 (...args) => a(f3(...args)) = f1(f2(f3(...args)))

通過上面的推導(dǎo),證實(shí)了先前得出的結(jié)論

compise(f, g, h) = (...args) => f(g(h(...args)))
applyMiddleware 分析

通過上面的分析,我們知道 compose 是對中間件的串聯(lián),那么 applyMiddleware 就是對中間件的應(yīng)用了。最終返回 createStore 中的方法以及經(jīng)過中間件包裝處理過的 dispatch 方法。

export default function applyMiddleware(...middlewares) {
  return createStore => (...args) => {
    const store = createStore(...args)
    let dispatch = () => {
      throw new Error(
        `Dispatching while constructing your middleware is not allowed. ` +
          `Other middleware would not be applied to this dispatch.`
      )
    }
    let chain = []

    const middlewareAPI = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args)
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

我們通過一個(gè)具體的中間件 redux-thunk,來查看它內(nèi)部到底是怎么來執(zhí)行加載的中間件的。

function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => next => action => {
    if (typeof action === "function") {
      return action(dispatch, getState, extraArgument);
    }

    return next(action);
  };
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

中間件中包含了三個(gè)箭頭函數(shù),在 applyMiddleware 中的 map 操作后,返回了第二層箭頭函數(shù),所以 chain 中存儲(chǔ)的是各個(gè)中間件的第二層函數(shù)。

根據(jù) compose 的分析,

dispatch = compose(...chain)(store.dispatch)
等于
dispatch = f1(f2(f3(store.dispatch)))

我們先執(zhí)行第三個(gè)中間件,并把返回結(jié)果作為第二個(gè)中間件的入?yún)⒗^續(xù)執(zhí)行,以此類推,下一個(gè)中間件的入?yún)⑹巧弦粋€(gè)中間件的返回。如果說這里第三個(gè)中間件是上面的 redux-thunk,那么函數(shù)中的 next 就是 store.dispatch,返回第三個(gè)箭頭函數(shù) action。這里返回的第三個(gè)箭頭函數(shù),就是第二個(gè)中間件的 next 形參。以此類推,第二個(gè)返回的 action 就是第一個(gè)中間件的 next 形參。但是這里都還沒真正開始執(zhí)行中間件。

當(dāng)我們外部調(diào)用 store.dispatch(action) 方法的時(shí)候,才要真正開始執(zhí)行各個(gè)中間件。首先執(zhí)行中間件 f1,當(dāng)執(zhí)行到 next 的時(shí)候,開始執(zhí)行第二個(gè)中間件 f2,以此類推直到最后一個(gè)中間件,調(diào)用原生 store.dispatch 方法。

之所以要寫這么繞,也是為了符合 redux 單一數(shù)據(jù)源的原則,applyMiddleware 的寫法保證了 action 的流向,而且每一步的數(shù)據(jù)變化都是可以追蹤的。

其他

對比了 4.0.0-beta.1 之前版本的 applyMiddleware 的區(qū)別,發(fā)現(xiàn)內(nèi)部 dispatch 從之前的 store.dispatch 改成了現(xiàn)在的直接拋出一個(gè)錯(cuò)誤。根據(jù)這個(gè) issues 的討論,在中間件頂層調(diào)用了 store.dispatch,結(jié)果導(dǎo)致無法執(zhí)行后面的中間件。這個(gè)調(diào)用應(yīng)該是在處理 map 操作的時(shí)候執(zhí)行的,此時(shí)的 applyMiddleware 還沒執(zhí)行完,store.dispatch 調(diào)用的還是原生 createStroe 中的方法才導(dǎo)致的這個(gè)問題。

另外如果在中間件中即 action 層使用 dispatch 會(huì)怎樣呢?我們知道我們可以通過 next 進(jìn)入到下個(gè)中間件,那如果調(diào)用 store.dispatch 的話又會(huì)從外層重新來一遍,假如這個(gè)中間件內(nèi)部只是粗暴的調(diào)用 store.dispatch(action) 的話,就會(huì)形成死循環(huán)。如下圖所示

參考
redux middleware 詳解

Dispatching in a middleware before applyMiddleware completes

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/93857.html

相關(guān)文章

  • Redux原理分析

    摘要:調(diào)用鏈中最后一個(gè)會(huì)接受真實(shí)的的方法作為參數(shù),并借此結(jié)束調(diào)用鏈。總結(jié)我們常用的一般是除了和之外的方法,那個(gè)理解明白了,對于以后出現(xiàn)的問題會(huì)有很大幫助,本文只是針對最基礎(chǔ)的進(jìn)行解析,之后有機(jī)會(huì)繼續(xù)解析對他的封裝 前言 雖然一直使用redux+react-redux,但是并沒有真正去講redux最基礎(chǔ)的部分理解透徹,我覺得理解明白redux會(huì)對react-redux有一個(gè)透徹的理解。 其實(shí),...

    sumory 評論0 收藏0
  • redux 源碼分析,實(shí)現(xiàn)一個(gè)迷你的redux

    摘要:實(shí)現(xiàn)一個(gè)先不考慮中間件,實(shí)現(xiàn)一個(gè)簡潔的實(shí)現(xiàn)是最主要的一個(gè)了,通過可以創(chuàng)建一個(gè)用來存放應(yīng)用中所有的,一個(gè)應(yīng)用只能有一個(gè)。方法是用來把每一個(gè)用方法包裹一下,因?yàn)榭赡苤皇欠祷匾粋€(gè)具有屬性的對象,只有用執(zhí)行才有意義。正好可以利用的特性實(shí)現(xiàn)這個(gè)效果。 實(shí)現(xiàn)一個(gè)redux 先不考慮中間件,實(shí)現(xiàn)一個(gè)簡潔的redux 實(shí)現(xiàn)createStore createStore是redux最主要的一個(gè)API了,...

    Ashin 評論0 收藏0
  • React 項(xiàng)目中Redux 間件的理解

    摘要:如果想學(xué)習(xí)項(xiàng)目的底層建設(shè),建議先去學(xué)習(xí)官網(wǎng)案例,之后在學(xué)習(xí)的使用中間件介紹目的是提供第三方插件的模式,改變的過程。 前言 React/Redux項(xiàng)目結(jié)束后,當(dāng)我在研究react-router源碼的時(shí)候發(fā)現(xiàn)當(dāng)中有一部分含中間件的思想,所以才想把中間件重新梳理一遍;在之前看redux了解到中間件,redux層面中間件的理解對項(xiàng)目前期比較有幫助,雖然項(xiàng)目中后期基本可以忽略這層概念;現(xiàn)在對這部...

    amc 評論0 收藏0
  • redux淺析

    摘要:概念是一個(gè)狀態(tài)管理容器使用可以更好的管理和監(jiān)測組件之間需要通信的數(shù)據(jù)。參考源碼參考鏈接 redux概念 redux是一個(gè)狀態(tài)管理容器,使用redux可以更好的管理和監(jiān)測組件之間需要通信的數(shù)據(jù)。 redux基本原則 單一數(shù)據(jù)源 在redux中,整個(gè)應(yīng)用保持一個(gè)數(shù)據(jù)源,數(shù)據(jù)源是一個(gè)樹形的結(jié)構(gòu) 狀態(tài)只讀 狀態(tài)只讀意思是不能直接修改,需要通過dispatch action方式才可以,返回的是一...

    galois 評論0 收藏0
  • 精益 React 學(xué)習(xí)指南 (Lean React)- 3.3 理解 redux 間件

    摘要:數(shù)組為新的數(shù)組,包含了方法將新的和結(jié)合起來,生成一個(gè)新的方法返回的新增了一個(gè)方法,這個(gè)新的方法是改裝過的,也就是封裝了中間件的執(zhí)行。 書籍完整目錄 3.3 理解 Redux 中間件 showImg(https://segmentfault.com/img/bVymkt); 這一小節(jié)會(huì)講解 redux 中間件的原理,為下一節(jié)講解 redux 異步 action 做鋪墊,主要內(nèi)容為: ...

    Kerr1Gan 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<