2017-10-13 1 views
0

Nouveau aux promesses, aimerait apprendre. J'ai ce tableau de shopIds:promesses.toutes avec des valeurs supplémentaires

let shopIdsArray = ['shop1','shop2','shop3']; 

et un appel de promesse externe

getProducts(shopId, 'products') //promise returns the products of this shop 

Malheureusement, la promesse ne retourne pas le shopId, seulement les produits, donc je dois garder en quelque sorte le shopId et Rangez-le avec les produits une fois la promesse faite. Mon approche actuelle est d'appeler la promesse à chaque shopId, et ajouter le résultat de chaque appel de promesse à un shopsAndProductsArray comme ceci:

shopsAndProductsArray.push({ 
    "id":shopId, 
    "products":products 
}); 

Plus tard, ma « promesse d'emballage » doit retourner le shopsAndProductsArray fini.

Mon code actuel (noeud, ES6) ressemble à:

updateProducts = new Promise(

    function (resolve, reject) { 
     let shopIdsArray = ['shop1','shop2','shop3']; 
     const shopsAndProductsArray = []; 
     let promisesArray = []; 

     shopIdsArray.forEach((shopId) => { 
      let promise = getProducts(shopId, 'products') 
        .then((products) => { 
         const shopInfoObject = { 
           "id":shopId, 
           "products":products 
         }; 
         console.log("sio: ",shopInfoObject); //prints shopIds and products fine. 
         shopsAndProductsArray.push(shopInfoObject); 
         promisesArray.push(promise); 
        }); 

     }); 

     Promise.all(promisesArray) 
      .then(function (shopsAndProductsArray) { 
       resolve(shopsAndProductsArray); //the shopsAndProductsArray is undefined? 
      }); 
    } 
); 

Sur résolution, le shopsAndProductsArray est ... pas vide, mais se compose du même nombre d'entrées que le shopIdsArray, mais les éléments du tableau sont indéfinis. Je devrais probablement mettre les promesses dans un tableau d'abord, puis travailler sur eux dans Promise.all, mais à ce moment-là j'ai perdu la référence à quel magasin id la promesse appartient. J'ai lu beaucoup d'autres exemples sur l'itération et les promesses et essayé de nombreuses autres façons, mais il semble que je n'ai pas entièrement compris ce que l'on appelle à quel point. Je suis sûr que remplir le tableau des promesses comme je le fais est faux, mais je n'avais aucune meilleure idée de la façon d'invoquer Promise.all.

Je pense que je pourrais réduire mes questions jusqu'à:

  1. Comment dois-je itérer sur les shopIds, appelant la promesse avec chacun?
  2. Comment puis-je conserver le shopId une fois qu'une promesse renvoie une liste de produits?
  3. Comment puis-je retourner le tableau des shopIds et des produits une fois que tous les shopIds ont été traités?

Merci d'avance pour toute aide.

EDIT: Merci beaucoup, Justelouise et Felix Kling. Je savais que je complaisais les choses, mais je ne pouvais pas mettre le doigt où. Je comprends maintenant ce qui me manquait, grâce à vos exemples. Je pense que vos réponses sont essentiellement égales et toutes deux bien expliquées. Je donne la coche d'acceptation à Justelouise parce qu'elle semble être le premier et Felix Kling a légèrement plus de réputation O_o.

+0

Vous appelez 'shopsAndProductsArray.push (exchangeInfoObject);' mais l'objet que vous créez est affecté à 'shopInfoObject'. –

+0

Toutes vos promesses se résolvent en 'undefined' - parce que votre' .then (products => 'ne renvoie rien ... ce qui explique pourquoi' shopsAndProductsArray' est un tableau de 'function non défini (shopsAndProductsArray)' –

+0

note: votre 'const shopsAndProductsArray = []; 'n'est jamais utilisé pour quoi que ce soit –

Répondre

1

Je pense que vous pouvez simplifier vos fonctions en tant que tel:

return Promise.all(shopIdsArray.map(shopId => { 
    return getProducts(shopId).then((products) => { 
    return { 
     id: shopId, 
     products, 
    }; 
    }); 
})); 

Promise.all retourne un tableau de promesses créées que vous itérez à travers le tableau via la fonction de carte où dans getProducts appel est exécuté pour chaque identifiant de boutique.Une fois les produits les données sont renvoyées, vous avez toujours accès à l'identifiant du magasin correspondant pour elle et retourner un nouvel objet composé de l'identifiant et les résultats

return { 
    id: shopId, 
    products, 
}; 

Enfin, Promise.all retourne un tableau contenant la valeur renvoyée pour chaque promesse exécutée en son sein.

1

Votre code peut être simplifié beaucoup à:

updateProducts = Promise.all(
    ['shop1','shop2','shop3'].map(
    id => getProducts(id, 'products').then(products => ({id, products})) 
) 
); 

C'est exactement la même approche que le vôtre, un peu moins bavard.

Depuis Promise.all déjà renvoie une promesse, il n'est pas nécessaire de mettre un new Promise(...) autour d'elle.

Si vous souhaitez convertir chaque élément d'un tableau en autre chose, alors Array#map est une méthode plus utile. Il applique le rappel passé à chaque élément du tableau et renvoie un tableau de ses valeurs de retour. Dans votre cas, vous voulez créer une promesse pour chaque ID de boutique, et c'est ce que fait

['shop1','shop2','shop3'].map(id => getProducts(id, 'products')) 

fait.

Maintenant, puisque vous ne voulez pas seulement d'obtenir les produits, mais aussi l'identification, nous devons modifier le résultat de getProducts un peu, ce qui est ce que le

.then(products => ({id, products})) 

fait. Il n'y a rien de vraiment spécial à ce sujet. Nous retournons simplement un objet avec les deux propriétés id et products au lieu de simplement le tableau products.

Avec Promise.all et Array#map vous n'avez pas besoin de garder « manuellement » trace des promesses (promisesArray) et les résultats (shopsAndProductsArray).