日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
ReduxMiddleware原理淺析

本文轉(zhuǎn)載自微信公眾號(hào)「 之家前端共享流」,作者張俊領(lǐng)。轉(zhuǎn)載本文請(qǐng)聯(lián)系之家前端共享流公眾號(hào)。

創(chuàng)新互聯(lián)長(zhǎng)期為數(shù)千家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開(kāi)放共贏平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為松山企業(yè)提供專業(yè)的成都網(wǎng)站建設(shè)、做網(wǎng)站,松山網(wǎng)站改版等技術(shù)服務(wù)。擁有十載豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開(kāi)發(fā)。

Redux 是一個(gè)基于Flux架構(gòu)的JavaScript 應(yīng)用狀態(tài)管理庫(kù),提供可預(yù)測(cè)性的狀態(tài)管理方案。其中,middleware更是Redux中一個(gè)重要的概念,它存在使得Redux應(yīng)用更加靈活、可擴(kuò)展、可維護(hù)。本文中,我們將探討 Redux middleware的運(yùn)行機(jī)制和實(shí)現(xiàn)原理,最后帶您輕松實(shí)現(xiàn)一個(gè)自己的middleware。無(wú)論你是初學(xué)者還是有一定經(jīng)驗(yàn)的開(kāi)發(fā)者,相信本文都能給你帶來(lái)一些新的啟示和技巧。讓我們一起探索Redux middleware的魅力吧!

什么是Middleware

Redux middleware是一種可插拔的機(jī)制,用于在 Redux 的dispatch函數(shù)被調(diào)用后, redcer處理action之前,對(duì)action 進(jìn)行攔截、變換、增強(qiáng)等操作。Redux middleware可以用于很多場(chǎng)景,例如:

異步操作:Redux本身是同步的,但是我們可以使用middleware來(lái)處理異步操作,例如發(fā)起網(wǎng)絡(luò)請(qǐng)求,等待數(shù)據(jù)返回后再更新store;

日志:用于記錄每個(gè)action的執(zhí)行過(guò)程,以便于調(diào)試和分析;

認(rèn)證和授權(quán):可以攔截所有action,然后進(jìn)行認(rèn)證和授權(quán),以確保只有授權(quán)用戶可以執(zhí)行某些操作。

middleware簡(jiǎn)化后的核心邏輯如下:

const middleware = store => next => action => {
  // do something before dispatching the action
  const result = next(action);
  // do something after dispatching the action
  return result;
};

通過(guò)以上代碼可以看出middleware本質(zhì)上就是一個(gè)接受store、next、action三個(gè)參數(shù)的函數(shù)。其中,store是Redux的store對(duì)象,next是dispatch函數(shù),action是當(dāng)前的action對(duì)象。

使用Middleware

在Redux中使用middleware非常簡(jiǎn)單,只需要在創(chuàng)建store的時(shí)候使用applyMiddleware函數(shù)將middleware應(yīng)用到store上即可,

例如:

import { createStore, applyMiddleware } from 'redux'import rootReducer from './reducers'
import middleware1 from './middleware/middleware1'
import middleware2 from './middleware/middleware2'
const store = createStore(
  rootReducer,
  applyMiddleware(middleware1, middleware2)
)

在上面的代碼中,我們使用了applyMiddleware函數(shù)將middleware1,middleware2應(yīng)用到store上。這樣,當(dāng)我們調(diào)用 store.dispatch(action) 時(shí),middleware就會(huì)被依次執(zhí)行,直到reducer處理action。

Middleware內(nèi)部運(yùn)行機(jī)制及原理剖析

我們通過(guò)上文的使用方式發(fā)現(xiàn),middleware是通過(guò)createStore來(lái)增強(qiáng)和擴(kuò)展原來(lái)的dispatch。下面我們就從createStore入手,逐步對(duì)middleware進(jìn)行剖析:

createStore源碼分析

//簡(jiǎn)化后的源碼
import { Action } from './types/actions'
import { Reducer } from './types/reducers'
export function createStore<
  S,
  A extends Action,
  Ext extends {} = {},
  StateExt extends {} = {}
>(
  reducer: Reducer,
  preloadedState?: PreloadedState | StoreEnhancer,
  enhancer?: StoreEnhancer
): Store & Ext {
  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState as StoreEnhancer
    preloadedState = undefined
  }
  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error(
        `Expected the enhancer to be a function. Instead, received: '${kindOf(enhancer)}'`
      )
    }
    return enhancer(createStore)(
      reducer,
      preloadedState as PreloadedState
    ) as Store & Ext
  }
  let currentReducer = reducer
  let currentState = preloadedState as S
  let currentListeners: Map | null = new Map()
  let nextListeners = currentListeners
  let listenerIdCounter = 0
  let isDispatching = false
  function ensureCanMutateNextListeners() {
    if (nextListeners === currentListeners) {
      nextListeners = new Map()
      currentListeners.forEach((listener, key) => {
        nextListeners.set(key, listener)
      })
    }
  }
  function getState(): S {
        ...
  }
  function subscribe(listener: () => void) {
         ...
    let isSubscribed = true
    ensureCanMutateNextListeners()
    const listenerId = listenerIdCounter++
    nextListeners.set(listenerId, listener)
    return function unsubscribe() {
      if (!isSubscribed) {
        return
      }
      if (isDispatching) {
        throw new Error('...')
      }
      isSubscribed = false
      ensureCanMutateNextListeners()
      nextListeners.delete(listenerId)
      currentListeners = null
    }
  }
  function dispatch(action: A) {
        ...
  }
  dispatch({ type: ActionTypes.INIT } as A)
  const store = {
    dispatch: dispatch as Dispatch,
    subscribe,
    getState
  } as unknown as Store & Ext
  return store
}

從以上代碼,createStore方法接收三個(gè)參數(shù):reducer、preloadedState和enhancer。如果傳入了enhancer則使用enhancer來(lái)增強(qiáng)store(實(shí)際上是通過(guò)重寫createStore來(lái)增強(qiáng)dispatch),否則就返回一個(gè)包含getState、dispatch和subscribe方法的store對(duì)象。其中,這里的第三個(gè)參數(shù)enhancer就是我們下文要分析的applyMiddleWare

applyMiddleware源碼分析

//簡(jiǎn)化后的源碼
export default function applyMiddleware(
  ...middlewares: Middleware[]
): StoreEnhancer {
  return createStore =>
    (
      reducer: Reducer,
      preloadedState?: PreloadedState
    ) => {
      const store = createStore(reducer, preloadedState)
      let dispatch: Dispatch = () => {
        throw new Error(
          'Dispatching while constructing your middleware is not allowed. ' +
            'Other middleware would not be applied to this dispatch.'
        )
      }
      const middlewareAPI: MiddlewareAPI = {
        getState: store.getState,
        dispatch: (action, ...args) => dispatch(action, ...args)
      }
      const chain = middlewares.map(middleware => middleware(middlewareAPI))
      dispatch = compose(...chain)(store.dispatch)
      return {
        ...store,
        dispatch
      }
    }
}

如上所示,先通過(guò)輪詢執(zhí)行middleware柯里化函數(shù)第一層來(lái)為每個(gè)middleware函數(shù)提供getState和dispatch;再通過(guò)compose將所有middleware串聯(lián)起來(lái)形成一個(gè)函數(shù)鏈,從而實(shí)現(xiàn)對(duì)Redux數(shù)據(jù)的攔截和處理,并最終返回一個(gè)增強(qiáng)版的dispatch。我們看到在applyMiddleWare中compose是核心邏輯,下面我們具體分析下compose是如何進(jìn)行middleware函數(shù)聚合的。

compose源碼分析

export default function compose(...funcs: Function[]) {
  if (funcs.length === 0) {
    // infer the argument type so it is usable in inference down the line
    return (arg: T) => arg
  }
  if (funcs.length === 1) {
    return funcs[0]
  }
   return funcs.reduce((a, b) => (...args) => a(b(...args)));
}

如上所示,這段代碼首先判斷funcs數(shù)組的長(zhǎng)度,如果長(zhǎng)度為0,則直接返回一個(gè)函數(shù);如果長(zhǎng)度為1,則直接返回funcs[0];如果長(zhǎng)度大于1,則使用reduce方法通過(guò)把后一個(gè)的middleware的結(jié)果當(dāng)成參數(shù)傳遞給下一個(gè)middleware的方式將funcs數(shù)組中的函數(shù)依次組合起來(lái)。這里的func也就是接收next即dispatch作為參數(shù)的middleware柯里化函數(shù)第二層,func執(zhí)行后會(huì)返回一個(gè)新函數(shù)action => next(action)。最終compose返回一個(gè)新函數(shù),并按照從右到左的順序依次調(diào)用每個(gè)func進(jìn)行處理,這個(gè)函數(shù)就是增強(qiáng)版的dispatch。

接下來(lái),我們可以用“把大象放冰箱”這個(gè)哲理題作為一個(gè)示例,來(lái)繼續(xù)加深對(duì)compose函數(shù)的理解:

function putElephantInFridge(){
  console.log('打開(kāi)冰箱門');
  console.log('把大象放進(jìn)去');
  console.log('關(guān)上冰箱門');
}

這個(gè)函數(shù)實(shí)現(xiàn)起來(lái)雖然簡(jiǎn)單,但不好進(jìn)行繼續(xù)擴(kuò)展。為了便于擴(kuò)展我們把這個(gè)大函數(shù)拆解并抽象化,讓每個(gè)函數(shù)都是獨(dú)立的,只負(fù)責(zé)完成自己的任務(wù),最后再實(shí)現(xiàn)一個(gè)通用函數(shù)來(lái)獲取最后的結(jié)果:

function openFridgeDoor() {
  console.log('打開(kāi)冰箱門');
}
function putSomethingInFridge(something) {
  console.log(`把${something}放進(jìn)去`);
}
function closeFridgeDoor() {
  console.log('關(guān)上冰箱門');
}
const putInFridge = (something)=>compose(closeFridgeDoor,()=>{putSomethingInFridge(something)},openFridgeDoor)();
const putInFridgeAndNotClose = (something)=>compose(()=>{putSomethingInFridge(something)},openFridgeDoor)();
putInFridge('牛奶'); // 打開(kāi)冰箱門  把牛奶放進(jìn)去  關(guān)上冰箱門
putInFridgeAndNotClose('蘋果'); // 打開(kāi)冰箱門  把蘋果放進(jìn)去

在上面的代碼中,我們使用compose函數(shù)將三個(gè)單獨(dú)的函數(shù)組合成了一個(gè)函數(shù)putInFridge,該函數(shù)接收一個(gè)參數(shù)something,并依次執(zhí)行三個(gè)步驟,最終將something放進(jìn)了冰箱中。另外,我們也可以將其中兩個(gè)函數(shù)組合成函數(shù)putInFridgeAndNotClose。由上我們看到,compose函數(shù)是非常實(shí)用的一個(gè)函數(shù),通過(guò)它可以將任意多個(gè)函數(shù)組合在一起,實(shí)現(xiàn)更加靈活和有序的函數(shù)調(diào)用,增強(qiáng)了程序的復(fù)用性、可讀性、可測(cè)性。

Middleware實(shí)現(xiàn)方式

在 Redux 應(yīng)用中,我們可以使用多種方式來(lái)實(shí)現(xiàn)middleware。下面我們將介紹兩種主要的實(shí)現(xiàn)方法:

基于洋蔥模型實(shí)現(xiàn)

用過(guò)express、koa同學(xué)應(yīng)該都知道它們也都有middleware概念,Redux middleware的實(shí)現(xiàn)和koa的洋蔥模型的機(jī)制相似。Redux middleware在dispatch action和到達(dá)reducer之間提供第三方擴(kuò)展點(diǎn),這種實(shí)現(xiàn)方式的代碼結(jié)構(gòu)類似于洋蔥,形成了一層層的包裹,每一層都可以執(zhí)行一些操作,在每一層中可以對(duì)action進(jìn)行處理。

基于裝飾器實(shí)現(xiàn)

基于裝飾器相對(duì)于基于洋蔥模型更加直觀和易于理解,但是它需要使用 ES7 中的裝飾器語(yǔ)法,需要做一定的兼容性處理,這里不做過(guò)多闡述。

編寫自定義Middleware

基于以上簡(jiǎn)要剖析,我們接下來(lái)可以進(jìn)行開(kāi)發(fā)屬于自己的middleware。下文是一個(gè)最簡(jiǎn)單的middleware:

const loggerMiddleware = storeAPI => next => action => {
  console.log('dispatching', action)
  let result = next(action)
  console.log('next state', storeAPI.getState())
  return result
}

這個(gè)簡(jiǎn)易版的logger負(fù)責(zé)在控制臺(tái)中打印出當(dāng)前動(dòng)作的類型及當(dāng)狀態(tài)發(fā)生變化時(shí)打印出最新的狀態(tài)。使用它可以幫助開(kāi)發(fā)人員更快地發(fā)現(xiàn)應(yīng)用中的異常。

為什么要使用storeAPI => next => action =>這種形式呢?

要回答這個(gè)問(wèn)題我們可以先來(lái)看下Redux三大原則:

  • 單一數(shù)據(jù)源
  • state是只讀
  • 使用reducer純函數(shù)進(jìn)行更改

Redux middleware的storeAPI參數(shù)包含了整個(gè)Redux store的狀態(tài)和dispatch方法,這保證了Redux應(yīng)用中只有一個(gè)單一的數(shù)據(jù)源;middleware中的狀態(tài)是只讀的,不能被直接修改狀態(tài);Redux middleware中的next函數(shù)它接收一個(gè)動(dòng)作作為參數(shù),并返回一個(gè)新的函數(shù)。因此,采用這種形式正是更好的遵循Redux的設(shè)計(jì)原則,確保Redux應(yīng)用程序的可預(yù)測(cè)性、可維護(hù)性和可擴(kuò)展性。另外,在Redux社區(qū)中也有對(duì)使用這種形式的不同聲音,他們認(rèn)為“there is essentially no need to split the arguments into different function calls”、“minor change could promote authors' familiarity and understanding, thus encourage the development of additional middleware to Redux”,關(guān)于這塊您可以自行擴(kuò)展閱讀。

總結(jié)

middleware是 Redux 應(yīng)用中的一個(gè)重要概念,Redux middleware的原理是基于Redux原則和函數(shù)式編程思想,通過(guò)函數(shù)柯里化和函數(shù)組合來(lái)實(shí)現(xiàn)對(duì)dispatch的增強(qiáng),使得在數(shù)據(jù)流傳遞過(guò)程中可以插入一些自定義的操作。最后,希望本文能夠幫助讀者加深對(duì)middleware原理的理解,助您開(kāi)發(fā)出更加穩(wěn)定、高效的react應(yīng)用。

參考:https://redux.js.org/tutorials/fundamentals/part-4-store#middlewarehttps://github.com/reduxjs/redux


網(wǎng)站欄目:ReduxMiddleware原理淺析
URL鏈接:
http://m.5511xx.com/article/dpgpsgj.html