J'utilise Firebase Cloud Firestore, cependant, je pense que cela peut être plus un problème de retour de promesse asynchrone vs synchrone JavaScript.
Je fais une requête pour obtenir les ID d'une collection, puis je passe en revue les résultats de cette requête pour rechercher des enregistrements individuels d'une autre collection en fonction de cet ID.
Ensuite, je veux stocker chaque enregistrement trouvé dans un tableau, puis renvoyer le tableau entier.
results.length
est toujours 0 car return results
se déclenche avant la fin de forEach. Si j'imprime results.length
de l'intérieur du forEach, il contient des données.
Comment puis-je attendre que le forEach soit terminé avant de revenir de la promesse extérieure et de la fonction extérieure elle-même?
getFacultyFavoritesFirebase() {
var dbRef = db.collection("users").doc(global.user_id).collection("favorites");
var dbQuery = dbRef.where("type", "==", "faculty");
var dbPromise = dbQuery.get();
var results = [];
return dbPromise.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
var docRef = db.collection("faculty").doc(doc.id);
docRef.get().then(function(doc) {
if (doc.exists) {
results.Push(doc);
}
})
});
console.log(results.length);
return results;
})
.catch(function(error) {
console.log("Error getting documents: ", error);
});
}
L'astuce consiste à remplir results
avec des promesses plutôt que le résultat. Vous pouvez ensuite appeler Promise.all()
sur ce tableau de promesses et obtenir les résultats souhaités. Bien sûr, vous ne pouvez pas vérifier si doc.exists
Avant de pousser la promesse, vous devrez donc y faire face une fois que Promise.all()
sera résolu. Par exemple:
function getFacultyFavoritesFirebase() {
var dbRef = db.collection("users").doc(global.user_id).collection("favorites");
var dbQuery = dbRef.where("type", "==", "faculty");
var dbPromise = dbQuery.get();
// return the main promise
return dbPromise.then(function(querySnapshot) {
var results = [];
querySnapshot.forEach(function(doc) {
var docRef = db.collection("faculty").doc(doc.id);
// Push promise from get into results
results.Push(docRef.get())
});
// dbPromise.then() resolves to a single promise that resolves
// once all results have resolved
return Promise.all(results)
})
.catch(function(error) {
console.log("Error getting documents: ", error);
});
}
getFacultyFavoritesFirebase
.then(results => {
// use results array here and check for .exists
}
Si vous avez plusieurs éléments de travail à effectuer en même temps qui proviennent d'une boucle, vous pouvez collecter toutes les promesses de tous les éléments de travail et attendre qu'ils se terminent tous par Promise.all () . La forme générale d'une solution possible ressemble à ceci:
const promises = [] // collect all promises here
items.forEach(item => {
const promise = item.doWork()
promises.Push(promise)
})
Promise.all(promises).then(results => {
// continue processing here
// results[0] is the result of the first promise in the promises array
})
Vous pouvez l'adapter à quelque chose qui convient à votre propre forme spécifique.