轮询多个端点时,Redux Saga 的产出非常缓慢

Redux Saga yields very slowly when polling multiple endpoints

我正在使用 redux-saga 同时轮询两个 API,我希望用 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 时,它需要几秒钟才能继续(而 UI 也卡住)- 可能是什么原因?

我在 redux-saga 文档中发现了一些模式,您可以使用这些模式通过使用 cancel 而不是 race 来解决这种情况。使用它将:

cancel the current Effect where the task is blocked at the moment of cancellation.

我添加了一个示例(尽可能与您的代码相同),在触发 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 将取消向下传播到任何子任务。

If the callee is still pending and the caller decides to cancel the operation, it triggers a kind of a signal that propagates down to the callee (and possibly to any deep operations called by the callee itself). All deeply pending operations will be cancelled.

export function* pollEventsSagaWorker() {
    try {
        while (true) {
            yield put(fetchEvents());
            yield delay(EVENT_POLL_INTERVAL);
        }
    } finally {
        if (yield cancelled()) {
            console.error('polling stopped');
        }
    }
}

检查此引用 task-cancellation