5
votes

Async / wait in foreach n'attend pas

J'essaye d'utiliser async et await dans une fonction qui utilise une boucle forEach . Malheureusement, je ne peux pas le faire fonctionner. Ce qui devrait se passer, c'est qu'il prend un tableau d'événements documents , les parcourt en boucle, ajoute des données supplémentaires, puis les pousse vers le tableau events . Ce tableau events est ensuite renvoyé par la fonction d'origine. Voici mon code:

async function getEvents() {
  ...
  var events = []
  await addExtrasToDocsForUser(docs, currentUserId, events)
  return events

}


var addExtrasToDocsForUser = (docs, currentUserId, events) => {
    return docs.forEach(async (eventDoc) => {
        const event = await addExtrasToDocForUser(eventDoc, currentUserId)
        events.push(event)
    })
}

En fait, la fonction getEvents () renvoie des événements sous forme de tableau vide avant le La boucle forEach est terminée. Comment résoudre ce problème?


0 commentaires

3 Réponses :


1
votes

En gros, c'est ce qui se passe à l'intérieur de forEach :

const addExtrasToDocsForUser = async (docs, currentUserId, events) => {
  for (let i=0; i<docs.length; i++) {
    const event = await addExtrasToDocForUser(docs[i], currentUserId);
    events.push(event);
  }
  return;
}

En fait, la véritable implémentation est ce qui suit , mais l'essentiel est que nous n'attendons pas le rappel à faire , donc utiliser une fonction qui renvoie une promesse n'attendra pas que la promesse soit résolue à chaque fois.

Votre code n'est pas complet et vérifiable donc je ne peux pas être sûr que ce qui suit fonctionne, mais il devrait probablement agir comme prévu:

Array.prototype.forEach = function (callback) {
  for (let index = 0; index < this.length; index++) {
    callback(this[index], index, this);
  }
};

Vous pouvez également consulter cet article de CodeBurst sur foreach + async / await


2 commentaires

Dans ma fonction getEvents () , dois-je dire wait addExtrasToDocsForUser (docs, currentUserId, events) ou puis-je supprimer le wait là-bas?


Gardez le wait . Si vous le supprimez, il lancera simplement la promesse, mais n'attendra pas que la promesse soit résolue en premier.



1
votes

Utilisez Promise.all et map pour obtenir toutes les promesses internes et en renvoyer une seule qui les attend toutes:

const addExtrasToDocsForUser = async (docs, currentUserId, events) => {
    return Promise.all(docs.map(async (eventDoc) => {
        const event = await addExtrasToDocForUser(eventDoc, currentUserId)
        events.push(event)
    }));
}


0 commentaires

0
votes

Pourquoi combinez-vous des fonctions synchrones et asynchrones?
Vous appelez wait addExtrasToDocsForUser (docs, currentUserId, événements) , mais votre fonction addExtrasToDocsForUser n'est pas async.

var someOperation = async (op0, op1) => {
	return op0+':'+op1
}

var fnWithForeach = async (docs, number, outputs)=>{
  return await docs.forEach(async (doc)=>{
	const output = await someOperation(doc, number)
	outputs.push(output) 
  })
}

async function getOutputs() {
  // ...
  var docs = ['A', 'B', 'C']
  var number = 10
  // ...
  var outputs = []
  await fnWithForeach(docs, number, outputs)
  return outputs
}

async function main() {
  // ...
  var outputs = await getOutputs()
  console.log(outputs)
  // ...
}

main()

Vous voulez faire quelque chose comme ceci:

var addExtrasToDocsForUser = async (docs, currentUserId, events) => {
  return await docs.forEach(async (eventDoc) => {
    const event = await addExtrasToDocForUser(eventDoc, currentUserId)
    events.push(event)
  })
}


0 commentaires