Redux Saga:如何在不阻止父调用的情况下等待生成和调用完成

时间:2019-01-10 22:28:09

标签: javascript redux redux-saga

我正在尝试添加redux saga函数,但无法正确链接

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变得畅通无阻且完整。
  • bc都填写完后,我想打电话给d

据我所知,没有办法做到这一点。 allfork将阻止a

现在要解决此问题,我先调用了c,然后生成了bd的组合,但这意味着bc可以不能同时运行。

2 个答案:

答案 0 :(得分:0)

为此,您需要一个单独的信令机制。我会为此使用channel

  • a首先创建一个频道
  • a产生dScheduler通过通道
  • a将通道作为参数传递给b
  • b对结尾的频道进行put
  • a在结束时对频道进行putc完成后)
  • 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,其中添加了控制台日志,并且延长了延迟,以便于验证行为。

Edit y2yx3rp7rv

Redux Saga文档的相关部分是here。具体来说,靠近底部的部分称为“使用Sagas之间的通讯渠道”。

答案 1 :(得分:0)

不如https://stackoverflow.com/a/54140525/4453205优雅。

我的答案还假设a只是调用bc(或仅执行两个任务)。

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()]);
}