问题
I'm trying to add a redux saga function but I can't get the chaining right
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*() {}
- I want to call
awhich will spawnband callc. - When
cis complete I wantato become unblocked and complete. - When
bandcboth complete I want to calld
From what I can tell there isn't a way to do this. all or fork will block a
To get around this for now I have c called first and a combo of b and d spawned after but that means b and c can't be running at the same time.
回答1:
To do this you need a separate signalling mechanism. I would use a channel for this.
afirst creates a channelaspawnsdSchedulerpassing the channelapasses the channel as an argument tobbdoes aputto the channel at the endadoes aputto the channel at the end (whencfinishes)dSchedulerdoes twotakes on the channel and then callsd
The code would look something like the following:
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*() {
};
Here's a CodeSandbox with console logs added and the delay lengthened to make it easy to verify the behavior:
The relevant part of the Redux Saga documentation is here. Specifically the section near the bottom called "Using channels to communicate between Sagas".
回答2:
Not as elegant as https://stackoverflow.com/a/54140525/4453205.
Also my answer assumes a does the job of just calling b and c(or two tasks only).
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()]);
}
来源:https://stackoverflow.com/questions/54137804/redux-saga-how-to-wait-for-spawn-and-call-to-complete-without-blocking-parent-c