Promise.all (). Then () résoudre?

95

Utilisation de Node 4.x. Lorsque vous avez une, Promise.all(promises).then()quelle est la bonne façon de résoudre les données et de les transmettre au suivant .then()?

Je veux faire quelque chose comme ça:

Promise.all(promises).then(function(data){
  // Do something with the data here
}).then(function(data){
  // Do more stuff here
});

Mais je ne sais pas comment obtenir les données au 2ème .then(). Je ne peux pas utiliser resolve(...)dans le premier .then(). J'ai compris que je pouvais faire ceci:

return Promise.all(promises).then(function(data){
  // Do something with the data here
  return data;
}).then(function(data){
  // Do more stuff here
});

Mais cela ne semble pas être la bonne façon de le faire ... Quelle est la bonne approche?

Jake Wilson
la source

Réponses:

142

Mais cela ne semble pas être la bonne façon de procéder.

C'est en effet la bonne façon de le faire (ou du moins une bonne façon de le faire). C'est un aspect clé des promesses, c'est un pipeline et les données peuvent être massées par les différents gestionnaires du pipeline.

Exemple:

const promises = [
  new Promise(resolve => setTimeout(resolve, 0, 1)),
  new Promise(resolve => setTimeout(resolve, 0, 2))
];
Promise.all(promises)
  .then(data => {
    console.log("First handler", data);
    return data.map(entry => entry * 10);
  })
  .then(data => {
    console.log("Second handler", data);
  });

( catchgestionnaire omis par souci de concision. Dans le code de production, toujours soit propager la promesse, soit gérer le rejet.)

Le résultat que nous en voyons est:

Premier gestionnaire [1,2]
Second handler [10,20]

... parce que le premier gestionnaire obtient la résolution des deux promesses ( 1et 2) sous forme de tableau, puis crée un nouveau tableau avec chacune de celles multipliées par 10 et le renvoie. Le deuxième gestionnaire obtient ce que le premier gestionnaire a renvoyé.

Si le travail supplémentaire que vous effectuez est synchrone, vous pouvez également le placer dans le premier gestionnaire:

Exemple:

const promises = [
  new Promise(resolve => setTimeout(resolve, 0, 1)),
  new Promise(resolve => setTimeout(resolve, 0, 2))
];
Promise.all(promises)
  .then(data => {
    console.log("Initial data", data);
    data = data.map(entry => entry * 10);
    console.log("Updated data", data);
    return data;
  });

... mais s'il est asynchrone, vous ne voudrez pas le faire car il finit par être imbriqué, et l'imbrication peut rapidement devenir incontrôlable.

TJ Crowder
la source
1
Intéressant. Je vous remercie. Alors n'est-il pas possible de donner rejectune valeur après la Promisefonction initiale ? Ou est-ce que lancer une erreur n'importe où dans la chaîne vous amènera au .catch()? Si tel est le cas, quel est l'intérêt rejecten premier lieu? Pourquoi ne pas simplement lancer une erreur? Merci encore,
Jake Wilson
6
@JakeWilson: Ce sont des questions différentes. Mais vous confondez deux choses distinctes: créer et régler la promesse et gérer la promesse. Lorsque vous créez et réglez la promesse, vous utilisez resolveet reject. Lorsque vous manipulez , si votre traitement échoue, vous lancez en effet une exception pour déclencher le chemin de l'échec. Et oui, vous pouvez également lever une exception à partir du Promiserappel d' origine (plutôt que d'utiliser reject), mais tous les échecs ne sont pas des exceptions.
TJ Crowder
1

Aujourd'hui, NodeJS prend en charge une nouvelle async/awaitsyntaxe. Ceci est une syntaxe simple et rend la vie beaucoup plus facile

async function process(promises) { // must be an async function
    let x = await Promise.all(promises);  // now x will be an array
    x = x.map( tmp => tmp * 10);              // proccessing the data.
}

const promises = [
   new Promise(resolve => setTimeout(resolve, 0, 1)),
   new Promise(resolve => setTimeout(resolve, 0, 2))
];

process(promises)

Apprendre encore plus:

Aminadav Glickshtein
la source
1
Comment puis-je passer des paramètres à chaque promesse individuelle du processus? @ Aminadav Glickshtein
bhaRATh