跳至主要内容

组合 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))
}
}
}