Promise.all (). Then () lösen?

94

Verwenden von Knoten 4.x. Wenn Sie einen haben, Promise.all(promises).then()wie können Sie die Daten richtig auflösen und an den nächsten weitergeben .then()?

Ich möchte so etwas machen:

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

Aber ich bin nicht sicher, wie ich die Daten zum 2. bekommen soll .then(). Ich kann nicht resolve(...)in der ersten verwenden .then(). Ich habe herausgefunden, dass ich das kann:

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

Aber das scheint nicht der richtige Weg zu sein ... Was ist der richtige Ansatz dafür?

Jake Wilson
quelle

Antworten:

140

Aber das scheint nicht der richtige Weg zu sein.

Das ist in der Tat der richtige Weg, es zu tun (oder zumindest ein richtiger Weg, es zu tun). Dies ist ein Schlüsselaspekt von Versprechungen, sie sind eine Pipeline und die Daten können von den verschiedenen Handlern in der Pipeline massiert werden.

Beispiel:

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);
  });

(Der catchHandler wurde der Kürze halber weggelassen. Propagieren Sie im Produktionscode immer entweder das Versprechen oder behandeln Sie die Ablehnung.)

Die Ausgabe, die wir daraus sehen, ist:

Erster Handler [1,2]
Zweiter Handler [10,20]

... weil der erste Handler die Auflösung der beiden Versprechen ( 1und 2) als Array erhält und dann ein neues Array mit jedem der mit 10 multiplizierten erstellt und zurückgibt. Der zweite Handler erhält, was der erste Handler zurückgegeben hat.

Wenn die zusätzliche Arbeit, die Sie ausführen, synchron ist, können Sie sie auch in den ersten Handler einfügen:

Beispiel:

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;
  });

... aber wenn es asynchron ist, möchten Sie das nicht tun, da es verschachtelt wird und die Verschachtelung schnell außer Kontrolle geraten kann.

TJ Crowder
quelle
1
Interessant. Danke dir. Ist es also nicht möglich, rejecteinen Wert nach der Anfangsfunktion zu erhalten Promise? Oder bringt Sie das Auslösen eines Fehlers irgendwo in der Kette zum .catch()? Wenn dies der Fall ist, worum geht rejectes dann überhaupt? Warum nicht einfach Fehler werfen?
Jake Wilson
6
@ JakeWilson: Das sind verschiedene Fragen. Aber Sie verwechseln zwei verschiedene Dinge: Erstellen und Einlösen des Versprechens und Behandeln des Versprechens. Wenn Sie das Versprechen erstellen und einhalten, verwenden Sie resolveund reject. Wenn Sie Behandlung , wenn Ihre Verarbeitung fehlschlägt, werfen Sie in der Tat eine Ausnahme den Ausfall Weg auszulösen. Und ja, Sie können auch eine Ausnahme vom ursprünglichen PromiseRückruf auslösen (anstatt zu verwenden reject), aber nicht alle Fehler sind Ausnahmen.
TJ Crowder
1

Heute unterstützt NodeJS neue async/awaitSyntax. Dies ist eine einfache Syntax und erleichtert das Leben erheblich

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)

Mehr erfahren:

Aminadav Glickshtein
quelle
1
Wie kann ich Parameter an jedes einzelne Versprechen aus dem Prozess übergeben? @ Aminadav Glickshtein
bhaRATh