eol
eol

Reputation: 24565

Reduce array of promises instead of mapping and filtering undefined/null values

Currently in our API-server code we have the following:

async someAsyncMethod() {
    // ...
    let products = await Promise.all(shopStructure.map(async entry => {
                try {
                    const serviceResponse = await this.requestService.someService(entry);
                    return ProductMapper.map(entry, serviceResponse);
                } catch (err) {
                    this.logger.error('...');
                    return undefined;
                }
            }));
    products = products.filter(s => s);
    return products;
}

How would I use reduce here in order to get rid of the filter operation?

I tried using the following:

async someAsyncMethod() {
    // ...
    const products = await Promise.all(shopStructure.reduce(async (accumulator, entry) => {
                try {
                    const serviceResponse = await this.requestService.someService(entry);
                    accumulator.push(ProductMapper.map(entry, serviceResponse));
                } catch (err) {
                    this.logger.error('...');
                }
                return accumulator;
            },[]));
    return products;
}

but this results in compile errors ("No overload matches this call", "Argument of type ... is not assignable to parameter of type <never>").

Maybe there's another elegant way to do this? Note that I deliberately use Promise.all instead of for...of for performance reasons.

Upvotes: 1

Views: 358

Answers (1)

CertainPerformance
CertainPerformance

Reputation: 370779

I don't think reduce is the right tool here. You need to wait for n Promises to resolve, where n is the length of the shopStructure; the input array and the array of Promises that Promise.all needs are one-to-one, so .map and Promise.all definitely is the right approach.

You can avoid using .filter if you want by pushing to an array instead:

async someAsyncMethod() {
  const products = [];
  await Promise.all(shopStructure.map(entry => (
    this.requestService.someService(entry)
      .then(serviceResponse => products.push(ProductMapper.map(entry, serviceResponse)))
      .catch(err => { this.logger.error('...'); })
  )));
  return products;
}

I don't think there's a good-looking way to use reduce, since the .map is already essential.

Upvotes: 2

Related Questions