Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

204
Visualizações
Javascript: How to wait for multiple promises to resolve within a loop before moving forward

I saw similarly asked questions but I am having a hard time applying it to my code.

I have the following piece of code:

  createSubmission(sub: Submission, files: Files[]): Promise {

    //first add files to storage and create the url array
    let urlArray: string[];
    return files.forEach(file => {
      var storageRef = this.storage.ref(`files/${file.name}`);
      return storageRef.put(file).then(()=> {storageRef.getDownloadURL().subscribe(url => {
        urlArray.push(url);
        if(urlArray.length === files.length){ //we are at the final element
          sub.filesUrls = urlArray;
          return this.finilize(sub);
        }
      })
    });
    });
  }

  finilize(sub: Submission){ //actually creates the submission
    
      let subRef = this.db.database.ref(`/submissions/${sub.medicUid}`).push(); 
      let subKey = subRef.getKey();
      sub.uid = subKey; 
      return subRef.update(sub);
  }

The caller of the first method (createSubmission) should receive a Promise. My code sequence is finilized when we return from the finilize method.

I want to continue after all the elements in the loop have been iterated, and the urlArray has been filled. It is filled when it has the same number of elements as the passed files array, that's why I placed this condition:

if(urlArray.length === files.length){...}

However, I get an error because the if condition means that Not all code paths return a value. So I believe I should ditch the if condition and wait for all promises to resolve before calling finalize, but I am not very clear on how to do it.

about 4 years ago · Juan Pablo Isaza
3 Respostas
Responde à pergunta

0

First of all foreach loop does not return anything, instead, it modifies the existing array.

Now come to the solution

you cannot use forEach when you want your code to wait for some async event. Instead, use a for of loop, and with that use await

async createSubmission(sub: Submission, files: Files[]): Promise {

    //first add files to storage and create the url array
    let urlArray: string[];
    for (const file of files) {
        const url = await this.getDownloadURL(file)
        urlArray.push(url)
    }
    sub.filesUrls = urlArray
    return this.finilize(sub)    
}

getDownloadURL(file):Promise{
    let storageRef = this.storage.ref(`files/${file.name}`);
    return new Promise((resolve, reject) => {
        storageRef.put(file).then(() => {
            storageRef.getDownloadURL().subscribe(url => {
                resolve(url)
            })
        })
    })
}

finilize(sub: Submission){ //actually creates the submission

    let subRef = this.db.database.ref(`/submissions/${sub.medicUid}`).push();
    let subKey = subRef.getKey();
    sub.uid = subKey;
    return subRef.update(sub);
}

Note: Code snippet may contain syntactical errors

about 4 years ago · Juan Pablo Isaza Relatório

0

I don't know what storageRef.getDownloadURL() is from (I assume it is related to Firebase and Angular) so I leave most of your code untouched assuming that it is correct and that you just want to know how to correctly deal with the Promise case.

There are two ways of solving the problem.

  1. Processing the files sequentially using await/async
async createSubmission(sub: Submission, files: Files[]): Promise {

  //first add files to storage and create the url array
  let urlArray: string[];
  
  for( let file of files ) {
    const storageRef = this.storage.ref(`files/${file.name}`);
    await storageRef.put(file)
    const url = await new Promise((resolve, reject) => {
      try {
         // pass resolve to subscribe. The subscribe will then call resolve with the url
         storageRef.getDownloadURL().subscribe(resolve)
         // you need to check if the callback to passed to subscribe
         // is guaranteed to be called, otherwise you need to
         // handle that case otherwise your code flow will 
         // stuck at this situation
      } catch (err) {
        reject(err)
      }
    })
    urlArray.push(url)
  }
  
  sub.filesUrls = urlArray;
  
  return this.finilize(sub);
}

finilize(sub: Submission) { //actually creates the submission

  let subRef = this.db.database.ref(`/submissions/${sub.medicUid}`).push();
  let subKey = subRef.getKey();
  sub.uid = subKey;
  return subRef.update(sub);
}
  1. If storageRef.put(file) does some network stuff and you want to parallelize that (which is not always a good idea), you can use Promise.all and Array.map.
async createSubmission(sub: Submission, files: Files[]): Promise {

  //first add files to storage and create the url array
  let urlArray: string[];

  urlArray = Promise.all(files.map(async(file) => {
    const storageRef = this.storage.ref(`files/${file.name}`);
    await storageRef.put(file)
    const url = await new Promise((resolve, reject) => {
      try {
        // pass resolve to subscribe. The subscribe will then call resolve with the url
        storageRef.getDownloadURL().subscribe(resolve)
        // you need to check if the callback to passed to subscribe
        // is guaranteed to be called, otherwise you need to
        // handle that case otherwise your code flow will 
        // stuck at this situation
      } catch (err) {
        reject(err)
      }
    })
    
    return url
  }))



  sub.filesUrls = urlArray;

  return this.finilize(sub);
}

finilize(sub: Submission) { //actually creates the submission

  let subRef = this.db.database.ref(`/submissions/${sub.medicUid}`).push();
  let subKey = subRef.getKey();
  sub.uid = subKey;
  return subRef.update(sub);
}

As you use TypeScript you should add the corresponding type information to my code.

YOu further should check if storageRef.getDownloadURL() provides a Promise API and if so replace new Promise and the subscribe with that one.

about 4 years ago · Juan Pablo Isaza Relatório

0

I think what you're looking for is "Promise.all()"

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

Promise.all resolves an array of Promises.

In this example urlArray will contain the resolved values of getDownloadUrl


    let urlArrayTasks = [];

    for(let file of files){
      urlArrayTasks.push(this.getDownloadURL(file));
    }

    let urlArray = await Promise.all(urlArrayTasks);
about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda