Search code examples
javascriptasynchronouses6-promise

Using async/await in a loop


I know there are a lot of similar questions out there already but none of them seem to solve this specific problem. I have a Javascript function that contains a forEach loop and inside the forEach loop, there are asynchronous calls.

The code roughly looks like this:

const handleConvert = () => {

    const refs = { ...imageRefs.current }

    // Outer loop
    Object.keys(refs).forEach(key => {
      
      // Inner loop
      refs[key].forEach(ref => {
        toPng(ref)
          .then((dataUrl) => {
            props.setImageUrls(old => {
              return {
                ..old,
                [key]: [...old[key], dataUrl]
              }
            })
          })
          .catch(err => {
            console.error(err)
          })
      })
    })
    setConverting(false)
    setConverted(true)
  }

refs is an object that contains 2 keys and each key has an array for it's value. It looks something like this:

{
  a: [1, 2, 3],
  b: [3, 4, 5]
}

The toPng() function returns a promise. I am trying to wait for all of those promises to resolve before executing the code after the outer forEach loop:

if (mounted) {
  setConverting(false)
  setConverted(true)
}

Is there a way to wait for all the promises to resolve before executing the code after the outer loop? Maybe with Promise.all()?


Solution

  • Nest another Promise.all to wait for each subarray to finish. Make sure to map and return every Promise to the caller so the Promise.all functions properly.

    Promise.all(
        Object.entries(refs)
            .map(([key, arr]) => Promise.all(
                arr.map(num =>
                    toPng(num).then(dataUrl => {
                        props.setImageUrls(old => ({ ...old, [key]: [...old[key], dataUrl] }))
                    })
                )
            ))
    )
        .then( // all done