redux-saga学习进阶篇二

Posted fe-linjin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了redux-saga学习进阶篇二相关的知识,希望对你有一定的参考价值。

今日学习目录

一、race进一步讨论

二、组合saga

三、取消任务caceled进一步讨论

?

一、race进一步讨论

有时候我们同时启动多个任务,但又不想等待所有任务完成,我们只希望拿到 胜利者:即第一个被 resolve(或 reject)的任务。 race Effect 提供了一个方法,在多个 Effects 之间触发一个竞赛(race)。

// 1. 触发一个远程的获取请求,并且限制了 1 秒内响应,否则作超时处理。
import  race, call, put  from 'redux-saga/effects'
import  delay  from 'redux-saga'

function* fetchPostsWithTimeout() 
  const posts, timeout = yield race(
    posts: call(fetchApi, '/posts'),
    timeout: call(delay, 1000)
  )

  if (posts)
    put(type: 'POSTS_RECEIVED', posts)
  else
    put(type: 'TIMEOUT_ERROR')

// 2. race 的另一个有用的功能是,它会自动取消那些失败的 Effects。
import  race, take, call  from 'redux-saga/effects'

function* backgroundTask() 
  while (true)  ... 


function* watchStartBackgroundTask() 
  while (true) 
    yield take('START_BACKGROUND_TASK')
    yield race(
      task: call(backgroundTask),
      cancel: take('CANCEL_TASK')
    )
  

二、 组合Sagas

虽然使用 yield* 是提供组合 Sagas 的惯用方式,但这个方法也有一些局限性

  • 你可能会想要单独测试嵌套的 Generator。这导致了一些重复的测试代码及重复执行的开销。 我们不希望执行一个嵌套的 Generator,而仅仅是想确认它是被传入正确的参数来调用。

  • 更重要的是,yield* 只允许任务的顺序组合,所以一次你只能 yield* 一个 Generator。

// 1. 直接使用 yield 来并行地启动一个或多个子任务
// 当 yield 一个 call 至 Generator,Saga 需要等待 Generator 处理结束, 
// 然后以返回的值恢复执行(或错误从子任务中传播过来,则抛出异常)
function* fetchPosts() 
  yield put( actions.requestPosts() )
  const products = yield call(fetchApi, '/products')
  yield put( actions.receivePosts(products) )


function* watchFetch() 
  while ( yield take(FETCH_POSTS) ) 
    yield call(fetchPosts) // 等待 fetchPosts 完成
  

// 2. yield 一个队列的嵌套的 Generators,将同时启动这些子 Generators(sub-generators),
// 并等待它们完成。 然后以所有返回的结果恢复执行:
function* mainSaga(getState) 
  const results = yield [call(task1), call(task2), ...]
  yield put(showResults(results))

// 3. 使用 effect 合并器将那些 Sagas 和所有其他类型的 Effect 合并。
function* game(getState) 
  let finished
  while(!finished) 
    // 必须在 60 秒内完成
    const score, timeout = yield race(
      score: call( play, getState),
      timeout: call(delay, 60000)
    )

    if (!timeout) 
      finished = true
      yield put(showScore(score))
    
  

三、取消任务进一步讨论

. 一旦任务被 fork,可以使用 yield cancel(task) 来中止任务执行。取消正在运行的任务

example:

一个可通过某些 UI 命令启动或停止的后台同步任务。 在接收到 START_BACKGROUND_SYNC action 后,我们 fork 一个后台任务,周期性地从远程服务器同步一些数

这个任务将会一直执行直到一个 STOP_BACKGROUND_SYNC action 被触发。 然后我们取消后台任务,等待下一个 START_BACKGROUND_SYNC action。

import  take, put, call, fork, cancel, cancelled, delay  from 'redux-saga/effects'
import  someApi, actions  from 'somewhere'

function* bgSync() 
  try 
    while (true) 
      yield put(actions.requestStart())
      const result = yield call(someApi)
      yield put(actions.requestSuccess(result))
      yield delay(5000)
    
   finally 
    if (yield cancelled())
      yield put(actions.requestFailure('Sync cancelled!'))
  


function* main() 
  while ( yield take(START_BACKGROUND_SYNC) ) 
    // 启动后台任务
    const bgSyncTask = yield fork(bgSync)

    // 等待用户的停止操作
    yield take(STOP_BACKGROUND_SYNC)
    // 用户点击了停止,取消后台任务
    // 这会导致被 fork 的 bgSync 任务跳进它的 finally 区块
    yield cancel(bgSyncTask)
  

// 取消 bgSyncTask 将会导致 Generator 跳进 finally 区块。
// 可使用 yield cancelled() 来检查 Generator 是否已经被取消。

2. 取消正在执行的任务,也将同时取消被阻塞在当前 Effect 中的任务。

举个例子,假设在应用程序生命周期的某个时刻,还有挂起的(未完成的)调用链:

function* main() 
  const task = yield fork(subtask)
  ...
  // later
  yield cancel(task)


function* subtask() 
  ...
  yield call(subtask2) // currently blocked on this call
  ...


function* subtask2() 
  ...
  yield call(someApi) // currently blocked on this call
  ...

// yield cancel(task) 触发了 subtask 任务的取消,反过来它将触发 subtask2 的取消。

3. 关于自动取消

除了上述的一些手动取消外,还存在一些自动取消的案例

  • 在race Effect中,除了最先完成任务的,其他都会被取消
  • 并行的Effect( yield [...] ),一旦其中的任何一个任务被拒绝了,并行的Effect将会被拒绝(受Promise.all启发)

以上是关于redux-saga学习进阶篇二的主要内容,如果未能解决你的问题,请参考以下文章

Django 进阶篇二

Netty进阶篇二关于Buffer内存

Python进阶篇二Pygame的结构

P18:Redux-saga获取TodoList列表

Python学习之路

Python学习之路