组合 Sagas
使用 yield*
为组合 Sagas 提供了一种通畅的方式,但这个方法也有一些局限性:
你可能会想要单独测试嵌套的 Generator。这导致了一些重复的测试代码及重复执行的开销。
我们不希望执行一个嵌套的 Generator,而仅仅是想确认它是被传入正确的参数来调用。更重要的是,
yield*
只允许任务的顺序组合,所以一次你只能 yield* 一个 Generator。
你可以直接使用 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) // waits for the fetchPosts task to terminate
}
}
yield 一个队列的嵌套的 Generators,将同时启动这些子 Generators(sub-generators),并等待它们完成。
然后以所有返回的结果恢复执行:
function* mainSaga(getState) {
const results = yield [ call(task1), call(task2), ...]
yield put( showResults(results) )
}
事实上,yield Sagas 并不比 yield 其他 effects(未来的 actions,timeouts,等等)不同。
这意味着你可以使用 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) )
}
}
}