Poczekaj na iteracje array.map w Promise.all [duplikat]

Dec 06 2020

Mam następujący kod, który powinien dodać elementy dla klientów, jeśli jeszcze nie istnieją. Wykonywanie powinno odbywać się równolegle.

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`);

Problem polega na tym, że wykonanie nie czeka na createCustomerItemrozwiązanie w przypadkach!productExists)

To jest dziennik

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.

Oczywiście All items should not be presentpowinien być ostatni.

Gdy wszystkie elementy już istnieją, proces wygląda dobrze.

Odpowiedzi

JulienD Dec 06 2020 at 18:46

Spróbuj z flatMap:

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

Zamiast zwracać tablicę tablicy obietnic, spłaszczy zawartość do prostej tablicy obietnic, czego Promise.alloczekuje.

NB Z Twojego pytania nie wynika, czy należy zachować grupowanie artykułów według klienta. Jeśli tak, zwróć uwagę, że to rozwiązanie zmienia strukturę danych na spłaszczoną listę, co powoduje utratę grupowania. Dodaj trochę customerIdw swoich items lub wypróbuj sugestię @ blex w komentarzach.

ShashanSooriyahetti Dec 06 2020 at 18:56

możesz zrobić coś takiego

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();

wyniki

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

demo źródłowe