0

I'm attempting to create a function that will execute simultaneously to send images for Cloud Firestore. At the moment I'm attempting to simulate a request with setTimeout to understand how the function works.

Although I can't seem to get it to work as expected:

const functionO = async () => {
    try {
      console.log('before')
      const datas = [1,2,3]
      await new Promise(async (resolve, reject) => {
        await datas.forEach((d) => {
          // This is simulating a request to firestore cloud
          setTimeout(() => {
            console.log(d)
          }, 1000)
        })
        resolve()       
      })      
      console.log('after')
    } catch (err) {
    }
  }

The output:

before
after
1
2
3

expected (the numbers can be in different orders, although I need to wait for the promise to finish to continue):

before
1
2
3
after

How I intend to use the function later on:

const functionO = async () => {
    try {
      console.log('before')
      const datas = [1, 2, 3]
      await new Promise(async (resolve, reject) => {
        images.forEach(async (image) => {
          const extension = image?.type?.split('/')[1]
          const reference = await storage().ref(
            `receitas/${userInfo?.uid}/uid.${extension}`,
          )
          reference.putFile(file)
        })
        resolve()
      })
      console.log('after')
    } catch (err) {}
  }

The intention is, if something fails on sending a image, it won't execute the rest of the function.

Nilton Schumacher F
  • 814
  • 3
  • 13
  • 43
  • To get your expected output you would need to send the requests synchronously, as there is no guarantee that 1, 2, 3 would be returned in that order. For example the last request may be served first depending on server load/queuing so the response may be 3, 1, 2. The point of async logic is that it is fired and handled when ready, not in any specific order/timing. – Rory McCrossan Jul 22 '23 at 15:12
  • @RoryMcCrossan how I would send it sequentially? – Nilton Schumacher F Jul 22 '23 at 15:13
  • In a loop, without async. However, I would suggest that async is the far better approach, therefore I would rethink why I need my requests to respond in order, and change that requirement. Alternatively you could fire them all asynchronously and sort the responses before working with them - assuming there's an ordinal value you can sort them all by. – Rory McCrossan Jul 22 '23 at 15:13
  • Actually, I would not need the request in order, just wait for it to resolve. It can be 3,1,2 or 2,3,1 but I need the rest to execute later – Nilton Schumacher F Jul 22 '23 at 15:14
  • In which case call `console.log('after')` when the Promise has been resolved using `then()`: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all – Rory McCrossan Jul 22 '23 at 15:18
  • Isn't `await` supposed to do that instead of using `then` – Nilton Schumacher F Jul 22 '23 at 15:27
  • `forEach` doesn't return a promise, so `await`ing it isn't going to really do anything. In particular it won't stop the loop simply running synchronously, which is why the `after` is getting logged sooner than you would like. You probably want to wrap `setTimeout` in a promise (hopefully your real API has a promise-version already) and then use `Promise.all` on the array. – Robin Zigmond Jul 22 '23 at 15:35
  • @RobinZigmond I have inserted a answer does that validate? – Nilton Schumacher F Jul 22 '23 at 17:12

2 Answers2

0

for...each only accepts synchronous functions, it does not work as expected with asynchronous stuff. You need to use a traditional for-loop or for..of. I can't tell you why this is like it is...

Maybe you can find more information in this thread: Using async/await with a forEach loop

NIC
  • 69
  • 3
0

I believe this is a solution

try { 
      const images = [{uri: someUri}, {uri: someUri}]

      const imagesPromise = await images.map(async (image) => {
        const imageRequest = new Promise<void>((resolve) => {
          const extension = image?.type?.split('/')[1]
          const reference = storage().ref(
            `receitas/${userInfo?.uid}/uid.${extension}`,
          )
          reference.putFile('')
          resolve()
        })
        return imageRequest
      })

      await Promise.all(imagesPromise)

      console.log('run after promise')
    } catch (error) {
      console.log('Error on submit receita', error)
    }
Nilton Schumacher F
  • 814
  • 3
  • 13
  • 43