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学习进阶篇二的主要内容,如果未能解决你的问题,请参考以下文章