Search code examples
javascriptes6-promiseredux-toolkit

How to execute Promise.all only after an array of API calls finishes and catch the error if one of them fails?


I am trying to implement a redux action that iterates an array of items making an API call for each; what I want is to set the success state only after all the items of the array have been successfully sent. But if one of them fails I want it to go to the catch and set the failure state instead.

What is happening now is that the setOpenAccountSuccess inside the Promise.all is run even before all the items are sent and even if one of them fails.

What would I need to change to make it work? Thanks in advance. Here is the code I have:

export const openAccounts = (data, userId, addressId) => async (dispatch) => {
  dispatch(AccountsReducer.setOpenAccountsLoading());

  try {

    const openAccountsPromise = data.selectedProducts.map(async product => {
      let formatedData = setOpenAccountAndProductData(data, userId, addressId, product);

      await AccountsService.openAccounts(formatedData);
    });

    Promise.all(openAccountsPromise).then(dispatch(AccountsReducer.setOpenAccountSuccess()));

  } catch(error) {
    dispatch(AccountsReducer.setOpenAccountFailure(error.response?.data));
  }

}

Solution

  • Make sure you return the Promise from AccountsService.openAccounts in the map loop to collect all of the promise values.

    Then await the Promise.all(openAccountsPromise) call. Since both the loop and the Promise.all are in the same try / catch scope, any of the failed promises will be caught in the catch block.

    export const openAccounts = (data, userId, addressId) => async (dispatch) => {
      dispatch(AccountsReducer.setOpenAccountsLoading());
    
      try {
        const openAccountsPromise = data.selectedProducts.map(product => {
          let formatedData = setOpenAccountAndProductData(data, userId, addressId, product);
          return AccountsService.openAccounts(formatedData);
        });
        
        await Promise.all(openAccountsPromise);
        dispatch(AccountsReducer.setOpenAccountSuccess();
    
      } catch(error) {
        dispatch(AccountsReducer.setOpenAccountFailure(error.response?.data));
      }
    }