Search code examples
node.jspromiseasync-awaites6-promise

Capture individual record in catch statement if any error occurs while processing data through Promise.all


I'm processing multiple records using Promise.all now if any error occurs I want to capture individual record in catch statement

I have written a method callApi now I'm calling callApi method in main code

try {
 let result = await callApi(res)
}
catch (err) {

}

async function callApi(records) {
  return Promise.all(
    records.map(async record => {
        await processRecord(record)
    })
  )
}

I want to display/capture individual record in catch block if any error occurs ex below

try {
 let result = await callApi(res)
}
catch (err) {
 console.log('Got error while processing this record', record)
}

But how I will get record variable in catch block


Solution

  • Since it's processRecord that may throw, if you want the record it's processing to be what is caught, rather than the actual error, catch the processRecord error, and throw the record:

    function callApi(records) {
      return Promise.all(
        records.map(record => (
          processRecord(record)
            .catch((err) => {
              throw record;
            })
        ))
      )
    }
    

    It may be useful to return both the record and the error when catching, though:

    try {
      let result = await callApi(res)
    } catch ({ err, record }) { // <--------
      console.log('Got error while processing this record', record);
      console.log(err);
    }
    
    function callApi(records) {
      return Promise.all(
        records.map(record => (
          processRecord(record)
            .catch((err) => {
              throw { err, record };
            })
        ))
      )
    }
    

    Note that because callApi already explicitly returns a Promise, there's no need to make it an async function.

    To wait for all requests to finish, and then check the errors on each, do something like:

    function callApi(records) {
      return Promise.all(
        records.map(record => (
          processRecord(record)
            .then(value => ({ status: 'fulfilled', value }))
            .catch(err => ({ status: 'rejected', reason: { record, err } }))
        ))
      );
    }
    
    const result = await callApi(res);
    const failures = result.filter(({ status }) => status === 'rejected');
    failures.forEach(({ reason: { record, err } }) => {
      // record failed for reason err
    });