【问题标题】:Do not fail whole task even if one of promises rejected即使其中一个承诺被拒绝,也不要让整个任务失败
【发布时间】:2020-08-27 15:36:01
【问题描述】:

在redux saga中,如果我们想处理多个promise,我们可以使用all(相当于Promise.all):

yield all(
   users.map((user) => call(signUser, user)),
);

function* signUser() {
   yield call(someApi);
   yield put(someSuccessAction);
}

问题是,即使其中一个promise(调用)失败,整个任务也会被取消。

我的目标是保持任务活着,即使其中一个承诺失败了。

在纯 JS 中我可以使用 Promise.allSettled 处理它,但在 redux saga 中正确的方法是什么?

编辑:仍然没有找到任何合适的解决方案,即使我将yield all 包装在try... catch 块中,即使其中一个调用失败,整个任务也会被取消。

【问题讨论】:

  • @Roamer-1888 谢谢!但我正在为 redux saga 寻找指定的解决方案
  • 语法稍有不同,原理相同。
  • @Roamer-1888 不是真的,sagas 保存在发电机上
  • Patrickkx,这是什么意思,能给我一个参考吗?

标签: javascript reactjs promise react-redux redux-saga


【解决方案1】:

其实你应该把你的 Promises 数组改成 Redux-Saga 的 all 方法,你应该像下面这样写:

yield all(
  users.map((item) =>
    (function* () {
      try {
        return yield call(signUser, item);
      } catch (e) {
        return e; // **
      }
    })()
  )
);

您传递一个自调用生成器函数来处理错误,而不是 throw 使用 return。因此,有两颗星的线(**)。

通过使用这种方式,您的所有异步操作都返回为已解决,all 方法从未被拒绝。

【讨论】:

  • 亲爱的@Patrickkx,我改变了整个答案并使用另一种方式。
  • 您可以定义和使用call 包装器而不是自调用生成器。干净一点codesandbox.io/s/…
  • 亲爱的@AlekseyL。 ,感谢您的可爱评论,即使我检查了 CodeSandBox,我也认为您的代码比我的代码要高一点,非常感谢,但我更喜欢我的答案,感谢我为您当前的正确答案留下了一些支持。?
【解决方案2】:

您可以自己实现它。有一个PR。见下例:

import { all, put, call, takeLatest } from 'redux-saga/effects';
import { createStoreWithSaga } from '../../utils';

const someSuccessAction = { type: 'SIGN_USER_SUCCESS' };

function someApi(user) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (user < 5) {
        resolve('success');
      } else {
        reject('failed');
      }
    }, 1000);
  });
}

const allSettled = (effects) =>
  all(
    effects.map((effect) =>
      call(function* settle() {
        try {
          return { error: false, result: yield effect };
        } catch (err) {
          return { error: true, result: err };
        }
      }),
    ),
  );

function* batchSignUser(action) {
  const r = yield allSettled(action.payload.users.map((user) => call(signUser, user)));
  console.log(r);
}

function* signUser(user) {
  const r = yield call(someApi, user);
  yield put(someSuccessAction);
  return r;
}

function* watchBatchSignUser() {
  yield takeLatest('SIGN_USER', batchSignUser);
}
const store = createStoreWithSaga(watchBatchSignUser);

const users = [1, 2, 3, 4, 5, 6, 7];
store.dispatch({ type: 'SIGN_USER', payload: { users } });

执行结果:

[
  { error: false, result: 'success' },
  { error: false, result: 'success' },
  { error: false, result: 'success' },
  { error: false, result: 'success' },
  { error: true, result: 'failed' },
  { error: true, result: 'failed' },
  { error: true, result: 'failed' }
]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-19
    • 1970-01-01
    • 1970-01-01
    • 2021-03-16
    相关资源
    最近更新 更多