组合 Saga
虽然使用 yield*
提供了一种组合 Saga 的惯用方式,但这种方法有一些局限性
您可能希望分别测试嵌套的生成器。这会导致测试代码中出现一些重复,以及重复执行的开销。我们不想执行嵌套的生成器,而只是确保对它的调用使用了正确的参数。
更重要的是,
yield*
仅允许对任务进行顺序组合,因此您一次只能yield*
到一个生成器。
您可以使用 yield
并行启动一个或多个子任务。当生成对生成器的调用时,Saga 将等待生成器终止,然后继续执行返回的值(如果错误从子任务传播,则抛出)。
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) // waits for the fetchPosts task to terminate
}
}
对嵌套生成器数组进行 yield 操作将并行启动所有子生成器,等待它们完成,然后继续执行所有结果。
function* mainSaga(getState) {
const results = yield all([call(task1), call(task2), ...])
yield put(showResults(results))
}
事实上,yield Sagas 与 yield 其他效果(未来操作、超时等)没有区别。这意味着您可以使用效果组合器将这些 Sagas 与所有其他类型组合起来。
例如,您可能希望用户在有限的时间内完成某个游戏。
function* game(getState) {
let finished
while (!finished) {
// has to finish in 60 seconds
const {score, timeout} = yield race({
score: call(play, getState),
timeout: delay(60000)
})
if (!timeout) {
finished = true
yield put(showScore(score))
}
}
}