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?
3 Réponses :
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
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.
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) })); }
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) }) }