Redux Saga: Как дождаться появления и вызова, чтобы не блокировать родительский вызов - PullRequest
0 голосов
/ 11 января 2019

Я пытаюсь добавить функцию саги с избыточностью, но не могу получить правильную цепочку

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 не могут быть запущены одновременно.

Ответы [ 2 ]

0 голосов
/ 18 января 2019

Не так элегантно, как https://stackoverflow.com/a/54140525/4453205.

Кроме того, мой ответ предполагает, что 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()]);
}
0 голосов
/ 11 января 2019

Для этого вам понадобится отдельный сигнальный механизм. Я бы использовал channel для этого.

  • a сначала создает канал
  • a порождает 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 с добавленными журналами консоли и увеличенной задержкой, чтобы упростить проверку поведения:

Edit y2yx3rp7rv

Соответствующая часть документации Redux Saga здесь . В частности, раздел внизу называется «Использование каналов для связи между сагами».

...