API接口的阻塞和非阻塞
/**
* 同步call(阻塞,必须完成一个,才能继续下一个yield)
* 异步fork(无阻塞)
*
*
* 监听未来的action take
*
*/
阻塞 / 非阻塞
名称 阻塞
takeEvery 否
takeLatest 否
takeLeading 否
throttle 否
take 是
take(channel) 有时 (请查看 API 参考)
take.maybe 是
put 否
put.resolve 是
put(channel, action) 否
call 是
apply 是
cps 是
fork 否
spawn 否
join 是
cancel 否
select 否
actionChannel 否
flush 是
cancelled 是
race 是
delay 是
all 当 array 或 object 中有阻塞型 effect 的时候阻塞。
// takeEvery并发任务的实现
import {fork, take} from "redux-saga/effects"
const takeEvery = (pattern, saga, ...args) => fork(function*() {
while (true) {
const action = yield take(pattern)
yield fork(saga, ...args.concat(action))
}
})
// takeEvery 可以让多个 saga 任务并行被 fork 执行
// takeLatest只执行最后一个任务
import {cancel, fork, take} from "redux-saga/effects"
const takeLatest = (pattern, saga, ...args) => fork(function*() {
let lastTask
while (true) {
const action = yield take(pattern)
if (lastTask) {
yield cancel(lastTask) // 如果任务已经结束,则 cancel 为空操作
}
lastTask = yield fork(saga, ...args.concat(action))
}
})
// takeLatest 不允许多个 saga 任务并行地执行。一旦接收到新的发起的 action,它就会取消前面所有 fork 过的任务(如果这些任务还在执行的话)。
// 在处理 AJAX 请求的时候,如果我们只希望获取最后那个请求的响应,takeLatest 就会非常有用。
// /取消fork异步任务
function* loginFlow() {
while (true) {
const { user, password } = yield take('LOGIN_REQUEST')
// fork return a Task object
const task = yield fork(authorize, user, password)
const action = yield take(['LOGOUT', 'LOGIN_ERROR'])
if (action.type === 'LOGOUT')
yield cancel(task)
yield call(Api.clearItem('token'))
}
}
// cancel Effect 不会粗暴地结束我们的 authorize 任务,相反它会给予一个机会执行清理的逻辑。
// 在 finally 区块可以处理任何的取消逻辑(以及其他类型的完成逻辑)。
// 由于 finally 区块执行在任何类型的完成上(正常的 return, 错误, 或强制取消),如果你想要为取消作特殊处理,有一个 cancelled
function* authorize(user, password) {
try {
const token = yield call(Api.authorize, user, password)
yield put({ type: 'LOGIN_SUCCESS', token })
yield call(Api.storeItem, { token })
return token
} catch (error) {
yield put({ type: 'LOGIN_ERROR', error })
} finally {
if (yield cancelled()) {
// ... put special cancellation handling code here
}
}
}
// 同时执行多个任务
import { call } from 'redux-saga/effects'
// 正确写法, effects 将会同步执行
const [users, repos] = yield[
call(fetch, '/users'),
call(fetch, '/repos')
]
// 当我们需要 yield 一个包含 effects 的数组, generator 会被阻塞直到所有的 effects 都执行完毕,或者当一个 effect 被拒绝 (就像 Promise.all 的行为)
//在多个 Effects 之间启动 race,有时候我们同时启动多个任务,但又不想等待所有任务完成,我们只希望拿到 胜利者:即第一个被 resolve(或 reject)的任务。
// race 的另一个有用的功能是,它会自动取消那些失败的 Effects
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' })
}
// 组合组合 Sagas方法使用
// 你可能希望用户在有限的时间内完成一些游戏
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))
}
}
}
//取消一个任务 Generator 跳进 finally 区块
// 除了手动取消任务,还有一些情况的取消是自动触发的。
// 在 race Effect 中。所有参与 race 的任务,除了优胜者(译注:最先完成的任务),其他任务都会被取消。
// 并行的 Effect (yield […])。一旦其中任何一个任务被拒绝,并行的 Effect 将会被拒绝(受 Promise.all 启发)。在这种情况中,所有其他的 Effect 将被自动取消。
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 cancel(task) 不会等待被取消的任务完成(即执行其 catch 区块)Effect 的行为和 fork 有点类似。 一旦取消发起,它就会尽快返回。一旦取消,任务通常应尽快完成它的清理逻辑然后返回。
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)
}
}
欢迎star本人github:https://github.com/flyku