即使其中一个Promise被拒绝,也不要让整个任务失败

IT技术 javascript reactjs promise react-redux redux-saga
2021-05-05 18:20:26

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

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

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

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

我的目标是保持任务活着,即使其中一项Promise失败。

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

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

2个回答

实际上,您应该将 Promises 数组更改all为 Redux-Saga方法,您应该像下面这样编写它:

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

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

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

你可以自己实现。有一个公关见下面的例子:

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' }
]