Я пытаюсь добавить функцию саги Redx, но я не могу получить правильную цепочку
const randomDelay = () => parseInt(Math.random() * 500)
const a = function*() {
yield spawn(b)
yield call(c)
}
const b = function*() {
yield delay(randomDelay())
}
const c = function*() {
yield delay(randomDelay())
}
const d = function*() {}
a
который будет порождать b
и вызывать c
.c
завершением я хочу стать разблокированы и полными. a
b
и c
оба завершены, я хочу позвонить d
Из того, что я могу сказать, нет способа сделать это. all
или fork
будет блокировать a
Чтобы обойти это сейчас, я вызвал c
первым и создал b
и d
после, но это означает, что b
и c
не могут работать одновременно.
Не так элегантно, как qaru.site/questions/16829778/....
Также мой ответ предполагает, что a
выполняет только вызовы b
и c
(или только две задачи).
import { delay } from "redux-saga";
import { all, cancel, put, takeEvery, spawn, call } from "redux-saga/effects";
const randomDelay = () => parseInt(Math.random() * 500);
export function* startTasks() {
let completed = yield call(a);
if (completed) {
yield call(d);
}
}
const a = function*() {
let b_finished = false;
const b = function*() {
yield delay(randomDelay());
yield put({ type: "B_DONE" });
b_finished = true;
};
const c = function*() {
yield delay(randomDelay());
yield put({ type: "C_DONE" });
};
const taskB = yield spawn(b);
yield call(c);
yield cancel(taskB);
return b_finished;
};
const d = function*() {
yield delay(randomDelay());
yield put({ type: "D_DONE" });
};
export function* watchStartTasks() {
yield takeEvery("START_TASKS", startTasks);
}
export default function* rootSaga() {
yield all([watchStartTasks()]);
}
Для этого вам понадобится отдельный сигнальный механизм. Я бы использовал channel
для этого.
dScheduler
прохождение каналаa
передает канал в качестве аргумента b
b
делает put
на канал в концеa
делает put
в канал в конце (когда заканчивается c
)dScheduler
делает два take
канала и затем вызывает d
Код будет выглядеть примерно так:
import { delay, channel } from "redux-saga";
import { spawn, call, put, take } from "redux-saga/effects";
const randomDelay = () => parseInt(Math.random() * 500);
const B_OR_C_COMPLETED = "B_OR_C_COMPLETED";
export const a = function*() {
const bcCompletedChannel = channel();
yield spawn(dScheduler, bcCompletedChannel);
yield spawn(b, bcCompletedChannel);
yield call(c);
yield put(bcCompletedChannel, B_OR_C_COMPLETED);
};
const b = function*(bcCompletedChannel) {
yield delay(randomDelay());
yield put(bcCompletedChannel, B_OR_C_COMPLETED);
};
const c = function*() {
yield delay(randomDelay());
};
const dScheduler = function*(bcCompletedChannel) {
yield take(bcCompletedChannel);
yield take(bcCompletedChannel);
yield call(d);
};
const d = function*() {
};
Здесь добавлен CodeSandbox с журналами консоли и увеличена задержка для упрощения проверки поведения:
Соответствующая часть документации Redux Saga находится здесь. В частности, раздел внизу называется "Использование каналов для связи между сагами".
b
не является частью желаемого поведения.Also my answer assumes a does the job of just calling b and c
, поэтому отменаB
будет означать отменуA