1

In the following code. I'm running a loop for the properties of formFields. As you can see, I'm using a counter to only run this.updatePanoCollection() when all the files have been uploaded with api.uploadFieldFile:

  // formFields = { logo: { file: ... }, thumbnail: { file: ... } }

  let toUploadCount = 0
  let uploadedCount = 0

  Object.entries(formFields).forEach(([key, upload]) => {
    if (!upload || !upload.file) return
    toUploadCount++
    api.uploadFieldFile('logo', upload.file).then(downloadUrl => {
      formFields[key] = downloadUrl
      const updatePayload = {
        id: this.currentPanoCollection.id,
        data: formFields
      }
      uploadedCount++
      if (toUploadCount === uploadedCount) {
        // This only runs once right now
        return this.updatePanoCollection(updatePayload)
      }
    }).then(() => {
      // But this runs twice. It should only run once.
    }).catch(err => this.handleError(err))
  })

Now the problem is that the code inside .then() runs twice.

How to change this code so it only runs once (after all the files have been uploaded)?

alex
  • 7,111
  • 15
  • 50
  • 77
  • Which `then` are you referring to that you only want to run once, the first or the second? Might want `Promise.all` – CertainPerformance Jun 13 '18 at 06:09
  • @CertainPerformance the second one. – alex Jun 13 '18 at 06:09
  • Possible duplicate of [When to use promise.all()?](https://stackoverflow.com/questions/38180080/when-to-use-promise-all) – maazadeeb Jun 13 '18 at 06:10
  • @MaazSyedAdeeb I'm not sure if I should use `promise.all`. I'm only returning one promise. When the files haven't been uploaded yet, the promise doesn't return. – alex Jun 13 '18 at 06:13

1 Answers1

2

Use Promise.all rather than having to maintain a count of completes, like this:

Promise.all(
  Object.entries(formFields).map(([key, upload]) => {
    if (!upload || !upload.file) return;
    return api.uploadFieldFile('logo', upload.file)
      .then(downloadUrl => {
      formFields[key] = downloadUrl
    })
  })
)
  .then(() => {
    // all have been uploaded
    const updatePayload = {
      id: this.currentPanoCollection.id,
      data: formFields
    }
    return this.updatePanoCollection(updatePayload);
  })
  .then(() => {
    // update is completed as well
  })
  .catch(err => this.handleError(err))
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Thanks a lot. It works! I rarely use `Promise.all`. How does `Promise.all` keep count of the uploads? For example how does it know there's 1 or 2 uploads? – alex Jun 13 '18 at 06:23
  • 1
    It will just wait for all `Promise`s in the array it's passed to resolve before resolving itself. So, for example, if there's `[, undefined]` then it will disregard the `undefined` and wait for the single `Promise`. – CertainPerformance Jun 13 '18 at 06:25