从Redux-Saga All获得结果,即使有失败

人气:42 发布:2023-01-03 标签: javascript reactjs redux-saga

问题描述

我有一个场景,其中我需要并行进行多个API调用。目前,代码使用redux-sagaall来完成以下操作:

try {
    const results = yield all(
      someIds.map(id =>
        call(axios.delete, `/api/somewhere/items/${id}`)
      )
    );
    console.log(results);
    yield put(someSuccessFunction)
} catch(e) {
    yield put(someFailureFunction)
}

在所有调用都成功的情况下,results会正确地记录为一组axios响应,包括headersrequeststatus等。但是,如果只有一个调用失败,代码就会跳到catch块。我无法知道哪个调用失败。

我读过How to handle array of requests in redux saga,但在那里的示例中,似乎公认的答案是在每个调用的基础上跟踪成功或失败。我需要知道所有调用是否都成功,如果成功,则发送成功操作。如果有任何呼叫失败,我需要知道哪些呼叫失败,并调度失败或部分失败操作。它可能如下所示:

try {
    const results = yield all(
      someIds.map(id =>
        call(axios.delete, `/api/somewhere/items/${id}`)
      )
    );
    const success = results.every(result => result.status === 200);
    const failure = results.every(result => result.status !== 200);
    const partialFailure =
      results.some(result => result.status === 200) &&
      results.some(result => result.status !== 200);
    
    if (success) put(someSuccessAction);
    if (failure) put(someFailureAction);
    if (partialFailure) put(somePartialFailureAction);

} catch(e) {
    yield put(someFailureFunction);
}

但是,当任何500响应跳到Catch块时,我似乎无法理解如何检索结果数组。要做到这一点,最佳策略是什么?

推荐答案

诀窍是为每个请求单独尝试..捕捉,并将成功或失败的结果映射到一个结构中,然后在该结构上运行各种数组操作。从本质上讲,它的工作原理类似于Promise.reflect。在本例中,它可能如下所示:

function* deleteById(id) {
  try {
    const result = yield call(axios.delete, `/api/somewhere/items/${id}`)
    if (result.status !== 200) throw new Error('Invalid status')
    return {v: result, status: 'fulfilled'}
  } catch (err) {
    return {e: err, status: 'rejected'}
  }
}

function* deleteSaga() {
  const results = yield all(
    someIds.map(id => call(deleteById, id))
  )
  const success = results.every(result => result.status === 'fulfilled')
  const failure = results.every(result => result.status === 'rejected')
  //...
}

为了可读性,我已经按id将请求分离到它自己的传奇中,尽管它也可以是内联生成器。

16