1

我在传奇效果中的 yield all 有问题,我在下面提供了我的示例代码

function* fetchData(item) {
  try {
    const data = yield call(request, url);
    yield put(fetchDataSuccess(data));
  } catch (error) {
    yield put(fetchDataFailure(error));
    throw error;
  }
}

function* fetchSummary(action) {
  try {
      yield all(
        list.map(item=>
          call(fetchData, item)
        )
      );
  } catch (error) {
    yield put(
      enqueueSnackbar({
        message: "Has Error",
        options: { variant: "error" }
      })
    );
  }
}

它的逻辑是我想调用多个请求(一些成功,一些失败)。

预期:如果请求失败,错误将在 yield all 之后被捕获,但那些成功请求仍然继续,它应该在单个成功请求之后调度操作“fetchDataSuccess”(Promise.all 可以这样做)

实际:如果请求失败,yield all 后会捕获错误,然后 saga 立即取消所有其他“fetchData”调用。

谁能帮我实现这个逻辑。提前致谢。

4

1 回答 1

2

您描述的“实际”行为与我在您的代码中看到的相符。一旦抛出任何错误,我们就离开try区块并进入catch区块。

当我们yield使用一系列效果时,生成器会被阻塞,直到所有效果都被解决或一个被拒绝(就像行为方式Promise.all一样)。-文档

如果您希望每个fetch都执行,那么您需要将try/catch 放在.map. true您可以映射到/值数组false或设置错误值。或者,如果您不介意拥有多个小吃店,您可以put enqueueSnackbar在里面fetchData而不是在fetchSummary.

这是一种方法:

// modified to return either true or false
function* fetchData(item) {
  try {
    const data = yield call(request, item);
    yield put(fetchDataSuccess({ item, data }));
    return true;
  } catch (error) {
    yield put(fetchDataFailure({ item, error }));
    return false;
  }
}

function* fetchSummary(action) {
  const results = yield all(
    action.payload.list.map((item) => call(fetchData, item))
  );
  // check if any of the results were false;
  const hasError = results.some((res) => !res);
  if (hasError) {
    yield put(
      enqueueSnackbar({
        message: "Has Error",
        options: { variant: "error" }
      })
    );
  }
}

代码沙盒演示

于 2021-03-04T00:50:18.250 回答