1

I'm processing a list in a loop that's run async returning a promise and I do not want to exit processing on exception, so I aggregate them and pass them to the resolve callback in an outer finally block. I'll like to know if this is an anti-pattern and if so, please provide a pointer on how to do correctly. Thanks.

Example

async doSomething(list) {
let errorCount = 0
let errors = []
return new Promise(async (resolve, reject) => {
  try {
    list.forEach(async (item) => {
      try {
        actionThatThrows(item)
      } catch (e) {
        errorCount++
        errors[errorCount] = e
      }
    })
  } catch (e) {
    errorCount++
    errors[errorCount] = e
  } finally {
    if (errorCount > 0) {
      resolve(errors)
    } else {
      resolve()
    }
  }
})

}

Krazibit312
  • 380
  • 2
  • 12

3 Answers3

8

Yes, this code employs several antipatterns:

I do not want to exit processing on exception but aggregate them

You might want to have a look at Wait until all ES6 promises complete, even rejected promises for that.

But you can do it without those as well, assuming you want sequential iteration:

async function doSomething(list) {
    const errors = [];
    for (let item of list) {
        try {
            await actionThatThrows(item);
        } catch (e) {
            errors.push(e);
        }
    }
    if (errors.length)
        return errors;
    else
        return …;
}
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
3

The errors are the result of your asynchronous computation so it globally looks legit.

Assuming that actionThatThrows returns a promise (it's unclear in your question and code), it looks like it could be written like this:

function doSomething(list) {
    let errors = []
    return Promise.all(list.map(
        item => actionThatThrows(item).catch(e => {
            errors.push(e);
        })
    )).then(()=>{
        return errors.length ? errors : undefined;
    });
}
Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
0

1) async doSomething is not invoking an await, so remove async 2) async in list.forEach is not invoking an await, so remove async 3) First catch will catch all. Second catch will never be hit, so remove second catch and finally

Code can be simplified to:

doSomething(list) {
    let errorCount = 0,
        errors = [];
    for (let item of list) {
        try {
            actionThatThrows(item); //I suppose this is not returning a promise
        } catch (e) {
            errorCount += 1;
            errors[errorCount] = e;
        }
    }
    if (errorCount > 0) {
        return errors; //return Promise.reject(errors);
    } else {
        //return Promise.resolve();
    }
}
Niels Steenbeek
  • 4,692
  • 2
  • 41
  • 50