Les promesses de multi-niveau JavaScript sont ignorées. ()

J'avais un problème avec plusieurs promesses. Ce que j'ai essayé de faire, c'est d'abord d'obtenir une liste d'articles de réception dans une catégorie donnée, puis, pour chaque article de réception, j'obtiens son détail et l'identification du reçu, après avoir reçu l'identifiant du reçu, je recherche l'identifiant du compte. Ensuite, j'obtiens les détails du compte en fonction de l'ID du compte. Voici mon code:

var query = // get receipt items under certain category var outerPromise = query.once('value').then(data => { var promises = []; var datasetarr = []; data.forEach(snapshot => { var itemData = // get receipt item unique push ID var query = // get details of receipt items var promise = query.once('value').then(data => { var itemDetail = // get receipt item detail if(type == subtype){ var receiptID = itemDetail.receiptID; var query = // query receipts table by receiptID return query.once('value').then(data => { data.forEach(snapshot => { snapshot.forEach(childSnapshot => { if(childSnapshot.key == receiptID){ var accountKey = // get accountID var query = // query accounts table return query.once('value').then(data => { var accountDetail = data.val(); var age = accountDetail.age; var gender = accountDetail.gender; console.log(age + ' ' + gender); datasetarr.push({age: age, gender: gender}); }); } }); }); }); } }); promises.push(promise); }); return Promise.all(promises).then(()=> datasetarr); }); 

J'ai réussi à imprimer le résultat de la console.log ci-dessus. Cependant, lorsque j'ai essayé d'imprimer ici, c'est quand la promesse est terminée:

 outerPromise.then((arr) => { console.log('promise done'); for(var i = 0; i < arr.length; i++){ console.log(arr[i].age + ' ' + arr[i].gender); } }); 

Je n'obtiens rien ici. La console affiche maintenant «promesse faite» d'abord avant tout autre résultat que j'ai imprimé ci-dessus.

Des idées? Merci d'avance!

Je vais fournir une explication plus détaillée dans quelques heures, j'ai un engagement préalable, ce qui signifie que je ne peux pas fournir de détails maintenant

La première étape d'une solution «facile» est de créer une fonction pour faire un tableau d'un instantané de base de firebase, afin d'utiliser map / concat / filter etc.

 const snapshotToArray = snapshot => { const ret = []; snapshot.forEach(childSnapshot => { ret.push(childSnapshot); }); return ret; }; 

Maintenant, le code peut être écrit comme suit

 // get list of receipt items under category var query // = // get receipt items under certain category var outerPromise = query.once('value').then(data => { return Promise.all(snapshotToArray(data).map(snapshot => { var itemData // = // get receipt item unique push ID var query // = // get details of receipt items return query.once('value').then(data => { var itemDetail // = // get receipt item detail if(type == subtype){ var receiptID = itemDetail.receiptID; var query //= // query receipts table by receiptID return query.once('value').then(data => { return Promise.all([].concat(...snapshotToArray(data).map(snapshot => { return snapshotToArray(snapshot).map(childSnapshot => { if(childSnapshot.key == receiptID){ var accountKey //= // get accountID var query //= // query accounts table return query.once('value').then(data => { var accountDetail = data.val(); var age = accountDetail.age; var gender = accountDetail.gender; console.log(age + ' ' + gender); return({age, gender}); }); } }).filter(result => !!result); }).filter(result => !!result))); }); } }); })).then([].concat(...results => results.filter(result => !!result))); }); 

Pour expliquer les questions dans les commentaires

[].concat utilisé pour ajouter le contenu de plusieurs tableaux à un nouveau tableau, c'est-à-dire

 [].concat([1,2,3],[4,5,6]) => [1,2,3,4,5,6] 

...snapshotToArray(data).map(etc

… est l'opérateur de propagation, utilisé comme argument pour une fonction, il prend le iterable et "l'étend" à plusieurs arguments

 console.log(...[1,2,3]) == console.log(1,2,3) 

Dans ce cas, snapshotToArray(data).map renvoie un tableau de tableaux, pour donner un exemple de connexion à la console

 console.log(...[[1,2],[3,4]]) == console.log([1,2], [3,4]) 

Ajoutant le concat

 [].concat(...[[1,2],[3,4]]) == [].concat([1,2],[3,4]) == [1,2,3,4] 

De sorte qu'il aplatie un tableau à deux niveaux à un seul niveau, c'est-à-dire

 console.log(...[[1,2],[3,4]]) == console.log(1,2,3,4) 

Donc, en résumé, ce que ce fragment de code fait est d'aplatir un tableau à deux niveaux

 filter(result => !!result) 

Il suffit simplement de "filtrer" tous les éléments du tableau qui sont "faux". Comme vous avez cette condition

 if(childSnapshot.key == receiptID){ 

Si c'est faux, le résultat sera undefined pour cette map – tous les autres résultats seront un tableau, et même les tableaux vides sont véridiques – c'est pourquoi le filtrage se fait si souvent! Il y a probablement une meilleure façon de faire tout cela, mais à moins que vous ne traitiez littéralement des millions d'articles, il n'y a pas de problème réel avec le filtrage de résultats vides comme celui-ci

Le résultat final est un tableau plat avec seulement les promesses renvoyées du code dans