我在redux-saga
频道中进行了一组操作。它们中的每个(或同时)可能由于令牌过期而失败。
如何暂停以后的操作以防止下次失败,在刷新令牌和取消暂停通道后重试已捕获的操作。
function* watchRequests() {
// a set of simultaneous actions which utilize access token from store
const requestChannel = yield actionChannel('*_REQUEST')
while (true) {
try {
const { payload } = yield take(requestChannel)
yield fork(handleRequest, payload)
} catch (error) {
if (error === 'EXPIRED_ACCESS_TOKEN') {
const newToken = yield call(refreshToken)
yield call(setAccessToken, newToken)
} else {
throw error
}
} finally {
// after success token refresh
// 1. retry catched action
// 2. unsuspend rest actions from channel
}
}
}
答案 0 :(得分:2)
在这里处理相同的概念,但是使用不同的配方。
下面是代码的关键部分,但请注意,它仍在进行中。
关键是派生了“ api.refreshSession”,并且在此任务仍在运行时,每个REFRESH_SESSION操作都将加入已在运行的任务,而不是启动新任务。
function* refreshSessionListener() {
let task;
while (true) {
const action = yield take(REFRESH_SESSION);
if (task === undefined || !task.isRunning()) {
task = yield fork(api.refreshSession);
}
// non-blocking join
yield fork(joinRefreshSessionTask, task, action);
}
}
function* joinRefreshSessionTask(task, action) {
const response = yield join(task);
if (response.status === 200) {
yield fork(action.onSuccess);
} else {
yield fork(action.onError, response);
}
}
export function* apiSaga(...args) {
const [fn, { type, payload, meta = {} }] = args;
try {
const data = yield call(fn, payload);
yield* okSaga(type, e);
} catch (e) {
if (e.tokenExpired) {
yield put({
type: REFRESH_SESSION,
onSuccess: apiSaga.bind(null, ...args),
onError: errorSaga.bind(null, type)
});
return;
} else {
yield* errorSaga(type, e);
}
}
}
runSaga(refreshSessionListener)
我在应用程序的其他部分使用上述内容:
import {apiSaga} from ...
function* listenToActions () {
yield takeEvery(POST_SOMETHING, apiSaga.bind(null, api.postSomething));
yield takeLatest(GET_SOMETHING, apiSaga.bind(null, api.getSomething));
}
runSaga(listenToActions);