Aguarde as iterações de array.map em Promise.all [duplicado]

Dec 06 2020

Eu tenho o seguinte código que deve adicionar itens para clientes se eles ainda não existirem. A execução deve ser paralela.

await Promise.all(
    customers.map(async (customer) => {
        return customer.items.map(async (item) => {
            return new Promise(async (resolve) => {
                const productExists = someArray.some(
                    (arrayValue) => arrayValue === item.id
                );
                if (!productExists) {
                    logger.info(
                    `customer item ${item.id} does not exist, creating...` ); await createCustomerItem(item.id); logger.info(`customer item ${item.id} created.`);

                    someArray.push(item.id);
                } else {
                    logger.info(`customer item ${item.id} already exists, skipping...`);
                }
                resolve(true);
            });
        });
    })

);

logger.info(`All items should now be present`);

O problema é que a execução não está esperando para createCustomerItemser resolvida nos casos de!productExists)

Este é o log

customer item 32310 does not exist, creating...
customer item ao does not exist, creating...
customer item ute does not exist, creating...
All items should not be present
customer item ao created.
customer item ute created.
customer item 32310 created.

Naturalmente, All items should not be presentdeve vir por último.

Quando todos os itens já existem, o processo parece bom.

Respostas

JulienD Dec 06 2020 at 18:46

Experimente com flatMap:

await Promise.all(
    customers.flatMap(async (customer) => {
        return customer.items.map(async (item) => {

Em vez de retornar um array de array de Promises, ele irá nivelar o conteúdo em um array simples de Promises, que é o que se Promise.allespera.

NB: Não fica claro em sua pergunta se o agrupamento de itens por cliente precisa ser conservado. Em caso afirmativo, observe que esta solução altera a estrutura de dados para uma lista simplificada, portanto, você perde o agrupamento. Adicione alguns customerIdaos seus itemou experimente a sugestão de @blex nos comentários.

ShashanSooriyahetti Dec 06 2020 at 18:56

você pode fazer algo assim

const fruitsToGet = ['apple', 'grape', 'pear']

const mapLoop = async () => {
  console.log('Start')

  const promises = await fruitsToGet.map(async fruit => {
    const numFruit = new Promise((resolve, reject) => {
      setTimeout(() => resolve(fruit), 1000)
    });
    return numFruit
  })
  const numFruits = await Promise.all(promises)
  console.log(numFruits)

  console.log('End')
}

mapLoop();

resultados

Start
["apple", "grape", "pear"]
End

demonstração de origem