日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

Redux异步中间件

發布時間:2024/1/17 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redux异步中间件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

曾經前端的革新是以Ajax的出現為分水嶺,現代應用中絕大部分頁面渲染會以異步流的方式進行。在Redux中,如果要發起異步請求,最合適的位置是在action creator中實現。但我們之前了解到的action都是同步情況,因此需要引入中間件讓action支持異步情況,如異步action(異步請求)為一個函數,或者利用promise來完成,或者是其他自定義的形式等等,下面的middleware就是用來處理這些不同異步action(或者說成actionCreator)的.另外,在Redux社區里還有其他一些處理異步的中間件,它們大同小異,這里就不一一分析了。

redux-thunk

redux-thunk 是 redux 官方文檔中用到的異步組件,實質就是一個 redux 中間件,thunk 簡單來說 就是一個封裝表達式的函數,封裝的目的是延遲執行表達式。

redux-thunk 是一個通用的解決方案,其核心思想是讓 action 可以變為一個 thunk ,這樣的話:

  • 同步情況:dispatch(action)
  • 異步情況:dispatch(thunk)

    thunk 本質上就是一個函數,函數的參數為 dispatch, 所以一個簡單的 thunk 異步代碼就是如下:

    this.dispatch(function (dispatch){setTimeout(() => {dispatch({type: 'THUNK_ACTION'}) }, 1000) })
  • 之前已經講過,這樣的設計會導致異步邏輯放在了組件中,解決辦法為抽象出一個 asyncActionCreator, 這里也一樣,我們就叫 thunkActionCreator 吧,上面的例子可以改為:

    export function createThunkAction(payload) {return function(dispatch) {setTimeout(() => {dispatch({type: 'THUNK_ACTION', payload: payload}) }, 1000)} } // someComponent.js this.dispatch(createThunkAction(payload))

    redux-thunk源碼:

    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;

    思路:當action為函數的時候,我們并沒有調用next或dispatch方法,而是返回action的調用。這里的action即為一個Thunk函數,以達到將dispatch和getState參數傳遞到函數內的作用。

    此時,action可以寫成thunk形式(ThunkActionCreator):

    function getweather(url,params){return (dispatch,getState)=>{fetch(url,params).then(result=>{dispatch({type:'GET_WEATHER_SUCCESS',payload:result,});}).catch(err=>{dispatch({type:'GET_WEATHER_ERROR',error:err,});}); }; }

    redux-promise

    其實?thunk?我們已經有了處理異步的能力, 但是每次我們要自己去手動觸發三個?action, 工作量還是很大的。現在?ajax?很多都會包裝為?promise?對象,,異步請求其實都是利用promise來完成的 因此我們可以對與?dispatch?增加一層判斷, 使得它具有處理具有?promise?屬性的?action?的能力。

    import {isFSA} from 'flux-standard-action';function isPromise(val){return next=>action=>{if(!isFSA(action)){return isPromise(action)? action.then(dispatch):next(action); }return isPromise(action.payload)? action.payload.then(result=>dispatch({...action,payload:result}),error=>{dispatch({...action,payload:error,error:true});return Promise.reject(error);}): next(action);}; }

    思路:redux-promise兼容了FSA標準(了解FSA可參考https://segmentfault.com/a/11...),也就是說將返回的結果保存在payload中。實現過程非常容易理解,即判斷action或action.payload是否為promise,如果是,就執行then,返回的結果再發送一次dispatch。

    此時,action可以寫成promise形式(promiseActionCreator):

    //利用ES7的async和awaita語法 const fetchData=(url,params)=>fetch(url,params);async function getWeather(url,params){const result=await fetchData(url,params);if(result.error){return{type:'GET_WEATHER_ERROR',error:'result.error',};}return{type:'GET_WEATHER_SUCCESS',payload:'result'}; }

    redux-saga

    redux-saga是redux社區一個處理異步流的后起之秀,它與上述方法最直觀的不同就是用generator代替了promise。的確,redux-saga是最優雅的通用解決方案,它有著靈活而強大的協程機制,可以解決任何復雜的異步交互,具體的,放在另一篇文章中詳細介紹。

    為action定制的自定義異步中間件

    在理想情況下,我們不希望通過復雜的方法去請求數據,而是希望通過如下形式一并完成在異步請求過程中的不同狀態:

    {url:'/api/weather.json',params:{city:encodeURL(city),}type:['GET_WEATHER','GET_WEATHER_SUCCESS','GET_WEATHER_ERROR'], }

    可以看到,異步請求action的格式有別于FSA。它并沒有使用type屬性,而使用了types屬性。在請求middleware中,會對action進行格式檢查,若存在url和types屬性,則說明這個action是一個用于發送異步請求的action。此外,并不是所有請求都能攜帶參數,因此params是可選的。

    const fetchMiddleware=store=>next=>action=>{if(!action.url || !Array.isArray(action.types)){return next(action);}const [LOADING,SUCCESS,ERROR]=action.types;next({type: LOADING,loading: true,...action, });fetch(action.url,{params:action.params}) .then(result=>{next({type:SUCCES,loading:false,payload:result,});}).catch(err=>{next({type:ERROR,laoding:false,error:err,});}); }

    使用middleware處理復雜異步流

    在實際場景中,我們不但有短連接請求,還有輪詢請求、多異步串聯請求,或是在異步中加入同步處理的邏輯。這時我們需要對一般異步中間件進行處理。

    輪詢

    輪詢是長連接的一種實現方式,它能夠在一定時間內重新啟動自身,然后再次發起請求。基于這個特性,我們可以在上一個中間件的基礎上再寫一個middleware,這里命名為redux-polling:

    import setRafTimeout,{clearRafTimeout} from 'setRafTimeout';export default ({dispatch,getState})=>next=>action{const {poolingUrl,params,types}=action;const isPollingAction=pollingUrl&&params&&types;if(!isPollingAction){return next(action); }let timeoutId=null; const startPolling=(timeout=0)=>{timeoutId=setRafTimeout(()=>{const pollingAction={...others,url:pollingUrl,timeoutId,};dispatch(pollingAction).then(data=>{if(data && data.interval && typeof data.interval=='number'){startPolling(data.interval*1000);} else{console.error('pollingAction should fetch data contain interval');} });},timeout);};startPolling();}export const clearPollingTimeout=(timeId)=>{if(timeoutId){clearRafTimeout(timeId);} };

    我們用到了raf函數,它可以讓請求在一定時間內重新啟動;startPolling函數為遞歸函數,這樣可以,滿足輪詢的請求;在API的設計上,還暴露了clearPollingTimeout方法,以便我們在需要時手動停止輪詢。

    最后,調用action來發起輪詢:

    { pollingurl:'/api/weather.json', params:{city:encodeURL(city),}, types:[null,'GET_WEATHER-SUCCESS',null], }

    對于長連接,還有其他多種實現方式,最好的方式是對其整體做一次封裝,在內部實現諸如輪詢和WebSocket。

    多異步串聯

    我們可以通過promise封裝來實現不論是否是異步請求,都可以通過promise來傳遞以達到一個統一的效果。

    const sequenceMiddlware=({dispatch,getState})=>next=>action=>{if(!Array.isArray(action)){return next(action);}return action.reduce((result,currAction)=>{return result.then(()=>{return Array.isArray(currAction)?Promise.all(currAction.map(item=>dispatch(item))):dispatch(currAction);});},Promise.resolve()); }

    在構建action creator時,會傳遞一個數組,數組中每一個值都是按順序執行的步驟。這里的步驟既可以是異步的,也可以是同步的。在實現過程中,我們非常巧妙地使用了Promise.resolve()來初始化action.reduce方法,然后使用Promise.then()方法串聯起數組,達到了串聯步驟的目的。

    function getCurrCity(ip){return {url:'/api/getCurrCity.json',param: {ip},types: [null,'GET_CITY_SUCCESS',null],} }return getWeather(cityId){return{url:'/api/getWeatherInfo.json',param:{cityId},types:[null,'GET_WEATHER_SUUCCESS',null],} }function loadInitData(ip){return[getCurrCity(ip),(dispatch,state)=>{dispatch(getWeather(getCityIdWithState(state)));},]; }

    這種方法利用了數組的特性,它已經覆蓋了大部分場景,當然,如果串聯過程中有不同的分支,就無能為力了。

    創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

    總結

    以上是生活随笔為你收集整理的Redux异步中间件的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。