首页 > 其他分享 >使用ES6生成器(Generators)和redux-saga与使用ES2017的async/await和redux-thunk相比的优缺点。

使用ES6生成器(Generators)和redux-saga与使用ES2017的async/await和redux-thunk相比的优缺点。

时间:2023-11-13 14:55:06浏览次数:39  
标签:ES6 生成器 yield call error LOGIN redux type

内容来自 DOC https://q.houxu6.top/?s=使用ES6生成器(Generators)和redux-saga与使用ES2017的async/await和redux-thunk相比的优缺点。

目前关于redux的最新讨论焦点是redux-saga/redux-saga。它使用生成器函数来监听/分发actions。

在我深入研究之前,我想了解使用redux-saga与下面使用redux-thunk和async/await的方法相比的优缺点。

一个组件可能如下所示,像往常一样分发actions。

import { login } from 'redux/auth';

class LoginForm extends Component {

  onClick(e) {
    e.preventDefault();
    const { user, pass } = this.refs;
    this.props.dispatch(login(user.value, pass.value));
  }

  render() {
    return (<div>
 <input type="text" ref="user" />
 <input type="password" ref="pass" />
 <button onClick={::this.onClick}>Sign In</button>
 </div>);
  } 
}

export default connect((state) => ({}))(LoginForm);

然后我的actions看起来像这样:

// auth.js

import request from 'axios';
import { loadUserData } from './user';

// 定义常量
// 定义初始状态
// 导出默认reducer

export const login = (user, pass) => async (dispatch) => {
    try {
        dispatch({ type: LOGIN_REQUEST });
        let { data } = await request.post('/login', { user, pass });
        await dispatch(loadUserData(data.uid));
        dispatch({ type: LOGIN_SUCCESS, data });
    } catch(error) {
        dispatch({ type: LOGIN_ERROR, error });
    }
}

// 更多actions...


// user.js

import request from 'axios';

// 定义常量
// 定义初始状态
// 导出默认reducer

export const loadUserData = (uid) => async (dispatch) => {
    try {
        dispatch({ type: USERDATA_REQUEST });
        let { data } = await request.get(`/users/${uid}`);
        dispatch({ type: USERDATA_SUCCESS, data });
    } catch(error) {
        dispatch({ type: USERDATA_ERROR, error });
    }
}

// 更多actions...


在redux-saga中,与上面的示例等效的代码如下:

export function* loginSaga() {
  while(true) {
    const { user, pass } = yield take(LOGIN\_REQUEST)
    try {
      let { data } = yield call(request.post, '/login', { user, pass });
      yield fork(loadUserData, data.uid);
      yield put({ type: LOGIN\_SUCCESS, data });
    } catch(error) {
      yield put({ type: LOGIN\_ERROR, error });
    }  
  }
}

export function* loadUserData(uid) {
  try {
    yield put({ type: USERDATA\_REQUEST });
    let { data } = yield call(request.get, `/users/${uid}`);
    yield put({ type: USERDATA\_SUCCESS, data });
  } catch(error) {
    yield put({ type: USERDATA\_ERROR, error });
  }
}

首先要注意的是,我们使用yield call(func, ...args)的形式调用API函数。call并不执行实际的效果,它只是创建一个普通对象,类似于{type: 'CALL', func, args}。执行任务的工作委托给redux-saga中间件,它负责执行函数并恢复生成器并返回结果。

主要优点是您可以在Redux之外使用简单的相等性检查来测试生成器。

const iterator = loginSaga()

assert.deepEqual(iterator.next().value, take(LOGIN\_REQUEST))

// 使用一些虚拟的操作恢复生成器
const mockAction = {user: '...', pass: '...'}
assert.deepEqual(
  iterator.next(mockAction).value, 
  call(request.post, '/login', mockAction)
)

// 模拟错误结果
const mockError = 'invalid user/password'
assert.deepEqual(
  iterator.throw(mockError).value, 
  put({ type: LOGIN\_ERROR, error: mockError })
)

请注意,我们通过向迭代器的next方法注入模拟数据来模拟API调用结果。与模拟函数相比,模拟数据要简单得多。

第二个要注意的是对yield take(ACTION)的调用。Thunk是由动作创建者在每个新动作(例如LOGIN_REQUEST)上调用的。即动作持续地“推送”给thunk,而thunk无法控制何时停止处理那些动作。

在redux-saga中,生成器“拉取”下一个动作。也就是说,它们可以控制何时监听某个动作以及何时不监听。在上面的示例中,流程指令放置在一个while(true)循环内,因此它将监听每个传入的动作,从某种程度上模拟了thunk的推送行为。

拉取的方式允许实现复杂的控制流程。例如,假设我们想要添加以下要求:

  • 处理LOGOUT用户动作
  • 在首次成功登录时,服务器返回一个以某个字段expires\_in存储的一段时间后过期的令牌,我们需要在每个expires\_in毫秒上后台刷新授权
  • 注意,在等待api调用的结果时(无论是初始登录还是刷新),用户可能会在其间注销。

如何使用thunk实现这一点,并为整个流程提供完整的测试覆盖率?以下是使用Sagas可能的实现方式:

function* authorize(credentials) {
  const token = yield call(api.authorize, credentials)
  yield put( login.success(token) )
  return token
}

function* authAndRefreshTokenOnExpiry(name, password) {
  let token = yield call(authorize, {name, password})
  while(true) {
    yield call(delay, token.expires\_in)
    token = yield call(authorize, {token})
  }
}

function* watchAuth() {
  while(true) {
    try {
      const {name, password} = yield take(LOGIN\_REQUEST)

      yield race([
        take(LOGOUT),
        call(authAndRefreshTokenOnExpiry, name, password)
      ])

      // 用户已注销,下一个while迭代将等待下一个LOGIN\_REQUEST动作

    } catch(error) {
      yield put( login.error(error) )
    }
  }
}

在上面的示例中,我们使用race来表达我们的并发需求。如果take(LOGOUT)赢得了比赛(即用户点击了注销按钮),比赛将自动取消authAndRefreshTokenOnExpiry后台任务。如果authAndRefreshTokenOnExpirycall(authorize, {token})调用的中间被阻塞,它也会被取消。取消会自动向下传播。

您可以在此流程的可运行演示中找到。

标签:ES6,生成器,yield,call,error,LOGIN,redux,type
From: https://www.cnblogs.com/xiaomandujia/p/17829068.html

相关文章

  • 生成器模式
    [实验任务一]:计算机组装使用建造者模式,完成下述任务:计算机组装工厂可以将CPU、内存、硬盘、主机等硬件设备组装在一起构成计算机,计算机的类型可以是笔记本,也可以是台式机。packageTutorial_5;publicclassClient{publicstaticvoidmain(String[]args){......
  • AI毕业设计生成器(基于AI大模型技术开发)
    这是一个辅助生成计算机毕业设计的工具,可以自动完成毕业设计的源码。它基于几百个github上面开源的java和python项目,运用tengsorflow技术,训练出了AI大模型。基本实现了计算机毕业设计生成器,能够初步生成Java或python基本源码。目前该项目处理实验阶段,还不成熟。体验地址https:......
  • 医院诊断证明一键生成器,画板+透明标签+取快照即可实现
    画板+透明标签+取快照就能实现一个自动生成诊断截图的工具,图片还是从网上随便找的,这个你可以自己随便换,但是我这里因为写教程所以加了水印,当然仅仅只是为了把自己的开发经验和思路以及代码逻辑分享一下而已,就是通过快照取画板截图,输出通过写到文件()命令即可实现,图片字节集信息通过......
  • 在线制作仿真病历证明软件,易语言实现病例报告生成器,取画板快照+标签+编辑框
    闲着无聊用易语言开发了一个病例生成器,当然我加了水印的,这个图片你就算截图你也用不了,模板是从百度图库搜的,很多,我就随便找了一个,然后实现逻辑就是加了一个画板,然后载入了素材图,素材信息元素上面加入透明标签,默认不支持透明,但可以用黑月支持库就可以实现标签的透明化,然后具体的实......
  • let是es6中声明变量的方式,有自己的作用域块,可以放变量,所以let绑定for循环时,每个i都有
    for(leti=0;i<2;i++){setTimeout(function(){console.log(i)},100);}for(vari=0;i<2;i++){setTimeout(function(){console.log(i)},100);}问:控制台打印的结果是?0122①Js是单线程的,Settimeout是异步宏任务,所以代码执行遇到异步的,就......
  • js常见的继承方式包括原型链继承、借用构造函数继承、组合继承、原型式继承、寄生式继
    js常见的继承方式包括原型链继承、借用构造函数继承、组合继承、原型式继承、寄生式继承、寄生组合式继承,以及ES6新增的class继承,但不包括关联继承https://www.cnblogs.com/Leophen/p/11401734.html构造函数继承是每次继承都会把父类的所有属性方法全部拷贝一份,而对于公用的方法......
  • 工商银行余额截图生成器,邮政农业建设中国招商,易语言画板即可实现
    用图片资源添加到画板的方式和编辑框改变标签的命令实现了一个自动生成余额的一个效果,原理非常非常简单,就是提前找对应余额模版,然后用PS摸出掉多余的内容,设计一个空白模版,然后通过多选框选择的方式把指定的图片资源加载到画板里面,然后在显示的画板图上面加入标签,点击按钮后会出现......
  • 四个id 生成器性能比较记录
    IdGeneratorSeata优化的雪花算法Seata基于改良版雪花算法的分布式UUID生成器分析关于新版雪花算法的答疑csharp移植代码publicclassIdGenerator{privatereadonlylongtwepoch=1588435200000L;privateconstintworkerIdBits=10;......
  • 银行APP虚拟金额软件,建设农业工商邮政余额生成器,易语言开源版
    用易语言开发了一个虚拟余额装逼软件,可以生成虚拟的余额截图,就是APP端的截图,用的画板组件,但是生成出来的图片是非常高清的,软件里面因为图片是缩放状态,所以看起来有点失真的感觉,生成图片的原理就是通过快照命令获取画板的句柄实现一个高清截图的效果,支持选择很多模版我都加进去了,但......
  • 招商银行余额截图生成器在线,虚拟金额中国农业邮政建设工商,易语言开源例子
    其实用易语言的画板写一个图片生成器真的非常简单,我这里都没用任何第三方的支持库,当然也可以用EXUI画板自绘功能,但是用这个默认的就足够了,而且画出来的图非常高清,软件框架里面比较模糊因为缩放的原因,然后主要实现功能就是用标签挡住了余额截图上面的关键字,标签要透明才行,然后通过......