alex
alex

Reputation: 7601

How to make the following code wait for and api call to be ready before resuming?

The following code loops through a formFields array. There are two types of fields: those with files to upload and those that don't. I'm keeping count of the "queued" fields and the "finished" ones, so I know when to update the form

const payload = {}
const fields = {
  queued: [],
  finished: []
}

formFields.forEach(field => {
  fields.queued.push(field)
  if (hasUploadFiles(field)) { // FOR FILE INPUTS
    utils.mapCallPromise(field.value, file => {
      api.uploadPhoto(file, field).then(uploadedPhoto => {
        payload[field.name] = uploadedPhoto
        fields.finished.push(field)
      })
    })
  } else {  // FOR NORMAL INPUTS
    payload[field.name] = field.value
    fields.finished.push(field)
  }
})

if (fields.queued.length === fields.finished.length) {
  console.log('use the payload to update the form')
}

The problem is api.uploadPhoto is triggering after if (fields.queued.length === fields.finished.length).

How to modify the code so if (fields.queued.length === fields.finished.length) triggers after api.uploadPhoto is done?

UPDATE:

This is api.uploadPhoto and utils.mapCallPromise:

api.uploadPhoto = async (file = {}, field = {}) => {
  if (utils.includes(api.usServers, api.env)) {
    return await usImageUpload.toFirebase(file, field)
  } else {
    return await cnImageUpload.toQCloud(file, field.userId, field.sizes)
  }
}

utils.mapCallPromise = (object, callback) => {
  return new Promise((resolve, reject) => {
    return Array.prototype.slice.call(object).map(value => {
      return resolve(callback(value))
    })
  })
},

Upvotes: 0

Views: 43

Answers (1)

Jaromanda X
Jaromanda X

Reputation: 1

Using Promise.all and array map method, you could do the following

Promise.all(formFields.map(field => {
    if (hasUploadFiles(field)) { // FOR FILE INPUTS
        return api.uploadPhoto(file, field).then(uploadedPhoto => {
            return {field, uploadedPhoto};
        });
    } else {  // FOR NORMAL INPUTS
        return {field};
    }
})).then(results => {
    //results is an array of objects that are either {field, uploadedPhoto} or just {field} 
});

Upvotes: 1

Related Questions