redux处理异步action解决方案_javascript技巧

来源:脚本之家  责任编辑:小易  

作为一名专业的爱狗人士,对于狗狗为什么会游泳我来科普一下。其实如果从历史发展的角度来说“物竞天择,适者生存”,都知道在很久之前的地球绝大部分是被海洋所覆盖的,所以对于动物来说,会游泳就成为了一项必备的技能了。从物种本身来说,狗狗相比较于人类有着天生的一个优势就是四肢行走头部高于身体的躯干,进入水中之后身体与水面接触的面积比较大从而可以获得更多的浮力,头部也可以更好的暴露在水面之上,并且不够灵活的四肢在手中会重复着简单的动作“狗爬式”滑动着游泳,而对于人类来说直立着进入水中虽然可以浮起来(游动起来很不方便),但是所获得的浮力并没有倒下整体躯干接触水面的浮力更大并且需要保证鼻子能够在外面经常换气(

如果没有中间件,store.dispatch只能接收一个普通对象作为action。在处理异步action时,我们需要在异步回调或者promise函数then内,async函数await之后dispatch。

上个世纪六十年代北京还有用纸糊窗户的。那个时候用的纸叫高粱纸,跟现在的宣纸差不多,稍有点韧性,粘水就破。刮风是不会破的,因为窗棱间距小,纸张所承受的风压并不大。大家可以去看看古建筑的门窗就明白了。古建筑的门窗棱为什么那么有美术工艺性?那不仅仅是为了美观,更重要的是缩小窗户纸的间距,把风的压强由门窗木棱所承载。那么下雨怎么办?房檐。对,就靠房檐挡雨,以免雨水打湿窗纸。古代盖房是有讲究的,房高和探出来的房檐是有比例的,房越高房檐探出的距离越大。

dispatch({ type:'before-load' }) fetch('http://myapi.com/${userId}').then({ response =>dispatch({ type:'load', payload:response }) })

有价值,简单、易写、有内涵,所以一定要收藏下去,能值几万块。其实,我不明白中国人说我爱你,谐音应该是521啊,为啥变成520了呢。靠,就在我刚才前一个问题的时候,我想明白了,南方人有个发音叫“侬”,就是指你的意思。我爱侬,原来是这么来的啊,南方人比北方人浪漫,先发明的吗?呵呵。

这样做确实可以解决问题,特别是在小型项目中,高效,可读性强。 但缺点是需要在组件中写大量的异步逻辑代码,不能将异步过程(例如异步获取数据)与dispatch抽象出来进行复用。而采用类似redux-thunk之类的中间件可以使得dispatch能够接收不仅仅是普通对象作为action。例如:

家用投影仪作为家庭影院的重要成员,从最初的好几万元的高价,一路发展到现在,几千元到万元左右便能买到一个显示效果不错的投影仪,越来越多的家庭在装修的时候,客厅开始考虑舍弃传统的电视机,而选装投影仪。那到底普通人家的客厅,是该选用电视还是投影仪?我们从以下几点来对比一下电视机和投影仪的区别。首先是尺寸。目前主流电视的尺寸在52英寸至70英寸之间,对于客厅的空间来说,已经足够了,但是投影仪在画面尺寸方面有绝对的优势,大小调整灵活,最大基本能投射出200英寸的画面,仿佛置身于一间小小的私人影院之中。然后是空间。虽然现在的液晶电视越来越轻薄,但无论是放置在电视柜上还是挂墙安置,电视机都会占用一定的空间,

function load(userId){ return function(dispatch,getState){ dispatch({ type:'before-load' }) fetch('http://myapi.com/${userId}').then({ response =>dispatch({ type:'load', payload:response }) }) } } //使用方式 dispatch(load(userId))

使用中间件可以让你采用自己方便的方式dispatch异步action,下面介绍常见的三种。

1. 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;

2. redux-promise

使用redux-promise可以将action或者action的payload写成promise形式。 源码:

export default function promiseMiddleware({ dispatch }) { 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 })) .catch(error => { dispatch({ ...action, payload: error, error: true }); return Promise.reject(error); }) : next(action); }; }

3. Redux-saga

redux-saga 是一个用于管理应用程序 Side Effect(副作用,例如异步获取数据,访问浏览器缓存等)的 library,它的目标是让副作用管理更容易,执行更高效,测试更简单,在处理故障时更容易

3.1 基本使用

import { call, put, takeEvery, takeLatest} from 'redux-saga/effects'; //复杂的异步流程操作 function* fetchUser(action){ try{ const user = yield call(API.fetchUser, action.payload); yield put({type:"USER_FETCH_SUCCEEDED",user:user}) }catch(e){ yield put({type:"USER_FETCH_FAILED",message:e.message}) } } //监听dispatch,调用相应函数进行处理 function* mainSaga(){ yield takeEvery("USER_FETCH_REQUESTED",fetchUser); } //在store中注入saga中间件 import {createStore,applyMiddleware} from 'redux'; import createSagaMiddleware from 'redux-saga'; import reducer from './reducers'; import mainSaga from './mainSaga'; const sagaMiddleware = createSagaMiddleware(); const store = createStore(reducer,initalState,applyMiddleware(sagaMiddleware)); sagaMiddleware.run(mainSaga)

3.2 声明式effects,便于测试

为了测试方便,在generator中不立即执行异步调用,而是使用call、apply等effects创建一条描述函数调用的对象,saga中间件确保执行函数调用并在响应被resolve时恢复generator。

function* fetchProducts() { const products = yield Api.fetch('/products') dispatch({ type: 'PRODUCTS_RECEIVED', products }) } //便于测试 function* fetchProducts() { const products = yield call(Api.fetch, '/products') //便于测试dispatch yield put({ type: 'PRODUCTS_RECEIVED', products }) // ... } // Effect -> 调用 Api.fetch 函数并传递 `./products` 作为参数 { CALL: { fn: Api.fetch, args: ['./products'] } }

3.3 构建复杂的控制流

saga可以通过使用effect创建器、effect组合器、saga辅助函数来构建复杂的控制流。

effect创建器: take:阻塞性effect,等待store中匹配的action或channel中的特定消息。 put:非阻塞性effect,用来命令 middleware 向 Store 发起一个 action。 call:阻塞性effect,用来命令 middleware 以参数 args 调用函数 fn。 fork:非阻塞性effect,用来命令 middleware 以 非阻塞调用 的形式执行 fn select:非阻塞性effect,用来命令 middleware 在当前 Store 的 state 上调用指定的选择器

effect组合器:

race:阻塞性effect:用来命令 middleware 在多个 Effect 间运行 竞赛(Race)

function fetchUsersSaga { const { response, cancel } = yield race({ response: call(fetchUsers), cancel: take(CANCEL_FETCH) }) }

all: 当 array 或 object 中有阻塞型 effect 的时候阻塞,用来命令 middleware 并行地运行多个 Effect,并等待它们全部完成

function* mySaga() { const [customers, products] = yield all([ call(fetchCustomers), call(fetchProducts) ]) }

effect辅助函数:

takeEvery:非阻塞性effect,在发起(dispatch)到 Store 并且匹配 pattern 的每一个 action 上派生一个 saga

const takeEvery = (patternOrChannel, saga, ...args) => fork(function*() { while (true) { const action = yield take(patternOrChannel) yield fork(saga, ...args.concat(action)) } })

takeLatest:非阻塞性,在发起到 Store 并且匹配 pattern 的每一个 action 上派生一个 saga。并自动取消之前所有已经启动但仍在执行中的 saga 任务。

const takeLatest = (patternOrChannel, saga, ...args) => fork(function*() { let lastTask while (true) { const action = yield take(patternOrChannel) if (lastTask) { yield cancel(lastTask) // 如果任务已经结束,cancel 则是空操作 } lastTask = yield fork(saga, ...args.concat(action)) } })

throttle:非阻塞性,在 ms 毫秒内将暂停派生新的任务

const throttle = (ms, pattern, task, ...args) => fork(function*() { const throttleChannel = yield actionChannel(pattern) ​ while (true) { const action = yield take(throttleChannel) yield fork(task, ...args, action) yield delay(ms) } })

到此这篇关于redux处理异步action解决方案的文章就介绍到这了,更多相关redux 异步action内容请搜索真格学网以前的文章或继续浏览下面的相关文章希望大家以后多多支持真格学网!

扩展阅读,根据您访问的内容系统为您准备了以下内容,希望对您有帮助。

javascript状态容器是什么,怎么理解

Redux要解决什么问题?

随着 JavaScript 单页应用开发日趋复杂,JavaScript 需要管理比任何时候都要多的 state (状态)。 这些 state 可能包括服务器响应、缓存数据、本地生成尚未持久化到服务器的数据,也包括 UI 状态,如激活的路由,被选中的标签,是否显示加载动效或者分页器等等。

管理不断变化的 state 非常困难。如果一个 model 的变化会引起另一个 model 变化,那么当 view 变化时,就可能引起对应 model 以及另一个 model 的变化,依次地,可能会引起另一个 view 的变化。直至你搞不清楚到底发生了什么。state 在什么时候,由于什么原因,如何变化已然不受控制。 当系统变得错综复杂的时候,想重现问题或者添加新功能就会变得举步维艰。

Redux的设计借鉴Flux、 Elm、Immutable,它的出现就是为了解决state里的数据问题。Redux和Flux的主要区别是Redux里面是单一的数据源设计,而Flux(或者Reflux)里面有多个数据源。

Redux是如何工作的?

我们知道,在React中,数据在组件中是单向流动的。数据从一个方向父组件流向子组件(通过props),由于这个特征,两个非父子关系的组件(或者称作兄弟组件)之间的通信并不是那么清楚。

React并不建议直接采用组件到组件的通信方式,尽管它有一些特性可以支持这么做(比如先将子组件的值传递给父组件,然后再由父组件在分发给指定的子组件)。这被很多人认为是糟糕的实践方式,因为这样的方式容易出错而且会让代码向“拉面”一样不容易理解。

当然React也没有直接建议如何去处理这种情形,以下是React的文档中关于这部分的描述:

对于非父子关系的组件,你可以自己建立一个全局的事件系统,Flux的模式也是一种可行的方式。

Redux的出现就让这个问题的解决变得更加方便了。Redux提供一种存储整个应用状态到一个地方的解决方案(可以理解为统一状态层),称为“store”,组件将状态的变化转发通知(dispatch)给store,而不是直接通知其它的组件。组件内部依赖的state的变化情况可以通过订阅store来实现。

使用Redux,所有的组件都从store里面获取它们依赖的state,同时也需要将state的变化告知store。组件不需要关注在这个store里面其它组件的state的变化情况,Redux让数据流变得更加简单。这种思想最初来自Flux,它是一种和React相同的单向数据流的设计模式。


  • 本文相关:
  • 详解redux异步操作实践
  • javascript数组去重实现方法小结
  • javascript实现平滑无缝滚动
  • 详解javascript utc时间转换方法
  • 使用axios实现上传图片进度条功能
  • js实现重新加载当前页面或者父页面的几种方法
  • 基于javascript实现鼠标向下滑动加载div的代码
  • html页面如何象asp一样接受参数
  • js获取判断上传文件后缀名的示例代码
  • 如何通过settimeout理解js运行机制详解
  • innerhtml动态添加html代码和脚本兼容多个浏览器
  • javascript状态容器是什么,怎么理解
  • 网站首页网页制作脚本下载服务器操作系统网站运营平面设计媒体动画电脑基础硬件教程网络安全基础知识javascript类库表单特效广告代码网页特效黑客性质javascript技巧domnode.jsjs其它首页javascriptjavascript技巧详解redux异步操作实践javascript数组去重实现方法小结javascript实现平滑无缝滚动详解javascript utc时间转换方法使用axios实现上传图片进度条功能js实现重新加载当前页面或者父页面的几种方法基于javascript实现鼠标向下滑动加载div的代码html页面如何象asp一样接受参数js获取判断上传文件后缀名的示例代码如何通过settimeout理解js运行机制详解innerhtml动态添加html代码和脚本兼容多个浏览器js刷新页面方法大全js中settimeout()的用法详解js截取字符串常用方法详细整理js页面跳转常用的几种方式js打开新窗口的2种方式js数组与字符串的相互转换方法js设置cookie、读取cookie、删除js 将json字符串转换为json对象的js删除数组里的某个元素方法javascript深入理解js闭包一个级联菜单(ie only),不过代码很精简!js 验证码功能的三种实现方式js选项卡的实现方法javascript中string和stringbuffer的速度js 方法实现返回多个数据的代码js消除图片小游戏代码详解js根据百度地图提供经纬度计算两点距js修改onclick动作的四种方法(推荐)json对象和字符串互相转换json数据拼接和javascript通过prototype给对象定义属性用
    免责声明 - 关于我们 - 联系我们 - 广告联系 - 友情链接 - 帮助中心 - 频道导航
    Copyright © 2017 www.zgxue.com All Rights Reserved