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