#redux-saga
#redux-saga
Вопрос:
Я одновременно опрашиваю два API, используя redux-saga, и я хочу контролировать оба опроса с помощью race
действия, которое может остановить их оба:
function* root() {
yield all([
call(startSimulation),
takeEvery(RESTART_SIMULATION, stopAndStartSimulation),
takeEvery(STOP_SIMULATION, haltSimulation),
])
export function* startPolling(vin: string) {
yield all([call(pollEventsSagaWorker), call(pollStatusSagaWorker, vin)])
}
export function* initiateSimulation() {
const vin = yield select(vinSelector)
yield call(startPolling, vin)
}
export function* haltSimulation() {
const runningSimulation = yield select(simulationsDataSelector)
if (runningSimulation) {
yield put(deleteSimulation(runningSimulation.id))
}
}
export function* startSimulation() {
while (true) {
yield take(INIT_SIMULATION)
yield race([call(initiateSimulation), take(STOP_SIMULATION)])
}
}
export function* stopAndStartSimulation() {
yield put(stopSimulation())
// do some other stuff
}
stopSimulation()
является создателем действия (с STOP_SIMULATION
типом).
Вот пример саги опроса:
export function* pollEventsSagaWorker() {
while (true) {
try {
yield put(fetchEvents())
yield delay(EVENT_POLL_INTERVAL)
} catch (err) {
console.error('polling failed', err)
}
}
}
Проблема в том, что при вызове STOP_SIMULATION
требуется несколько секунд, пока все не сдвинется с мертвой точки (в то время как пользовательский интерфейс также зависает) — в чем может быть причина?
Ответ №1:
Я нашел некоторый шаблон в документах redux-saga, который вы можете использовать для решения этого вопроса, используя cancel
вместо race
. Его использование приведет:
отмените текущий эффект, при котором задача заблокирована в момент отмены.
Я добавил пример (настолько идентичный, насколько мог, вашему коду), который запускает эффект отмены сразу после STOP_SIMULATION
выполнения действия.
// THE CONTROL LOOP
export function* mainSaga() {
while (yield take(INIT_SIMULATION)) {
// starts the task in the background
const task = yield fork(pollEventsSagaWorker);
// wait for the user stop action
yield take(STOP_SIMULATION);
// user clicked stop.
// cancel the polling by causing the forked saga to enter its finally block
yield cancel(task);
}
}
Это приведет к pollEventsSagaWorker
распространению отмены вниз на любые подзадачи.
Если вызываемый абонент все еще ожидает, и вызывающий абонент решает отменить операцию, это запускает своего рода сигнал, который распространяется вниз к вызываемому абоненту (и, возможно, к любым глубоким операциям, вызываемым самим вызываемым абонентом). Все глубоко ожидающие операции будут отменены.
export function* pollEventsSagaWorker() {
try {
while (true) {
yield put(fetchEvents());
yield delay(EVENT_POLL_INTERVAL);
}
} finally {
if (yield cancelled()) {
console.error('polling stopped');
}
}
}
Проверьте эту ссылку на отмену задачи
Комментарии:
1. Спасибо, это решение красивее, решает мою проблему (что, по-видимому, произошло только при открытии devtools)