Warte auf mehr als eine gleichzeitige Warteoperation

Wie kann ich den folgenden Code so ändern, dass beide asynchronen Vorgänge ausgetriggers werden und gleichzeitig ausgeführt werden können?

const value1 = await getValue1Async(); const value2 = await getValue2Async(); // use both values 

Muss ich so etwas tun?

 const p1 = getValue1Async(); const p2 = getValue2Async(); const value1 = await p1; const value2 = await p2; // use both values 

TL; DR

Verwenden Sie das Muster nicht in der Frage, wo Sie die Versprechen erhalten, und warten Sie dann separat darauf; Verwenden Promise.all stattdessen Promise.all (zumindest für den Promise.all ):

 const [value1, value2] = await Promise.all([getValue1Async(), getValue2Async()]); 

Während Ihre Lösung die beiden Vorgänge parallel ausführt, wird die Ablehnung nicht ordnungsgemäß verarbeitet, wenn beide Versprechungen abgelehnt werden.

Einzelheiten:

Ihre Lösung führt sie parallel aus, wartet aber immer auf den ersten, bevor sie auf den zweiten wartet. Wenn Sie sie nur starten, parallel ausführen und beide Ergebnisse erhalten möchten, ist es in Ordnung. (Nein, es ist nicht, lesen Sie weiter …) Beachten Sie, dass wenn der erste (sagen wir) fünf Sekunden dauert und der zweite in einer Sekunde ausfällt, der Code die vollen fünf Sekunden wartet, bevor er dann ausfällt.

Leider gibt es zur Zeit keine Syntax, die man parallel abwarten kann, also haben Sie die Ungeschicklichkeit, die Sie aufgelistet haben, oder Promise.all . (Es gab Diskussionen von await.all oder ähnlichem , vielleicht eines Tages.)

Die Promise.all Version ist:

 const [value1, value2] = await Promise.all([getValue1Async(), getValue2Async()]); 

… was prägnanter ist und auch nicht auf die erste Operation wartet, wenn die zweite schnell ausfällt (zB in meinem obigen Beispiel von fünf Sekunden / einer Sekunde, wird das obige in einer Sekunde ablehnen, anstatt fünf zu warten) . Beachten Sie außerdem, dass bei Ihrem ursprünglichen Code, wenn das zweite Versprechen ablehnt, bevor das erste Versprechen verrechnet wird, möglicherweise ein “unhandled rejection” -Fehler in der Konsole auftritt (derzeit mit Chrome v61), obwohl dieser Fehler wohl unecht ist (weil Sie bewerkstellige schließlich die Ablehnung). Aber wenn beide Versprechen ablehnen, erhalten Sie einen echten unbehandelten Ablehnungserrors, weil der Kontrollfluss nie den Wert const value2 = await p2; erreicht2 const value2 = await p2; und somit wird die p2-Zurückweisung niemals behandelt.

Unbehandelte Ablehnungen sind ein Bad Thing ™ (so sehr, dass NodeJS bald den process bei wirklich unbehandelten Ablehnungen abbricht, genau wie unbehandelte Ausnahmen – weil sie das sind), also vermeiden Sie am besten das “Holen Sie das Versprechen, dann await es” -Muster in deiner Frage.

Hier ist ein Beispiel für den Unterschied im Timing im Fehlerfall (mit 500ms und 100ms anstelle von 5 Sekunden und 1 Sekunde) und möglicherweise auch mit dem argwöhnisch falschen unbehandelten Ablehnungserrors (öffnen Sie die echte Browserkonsole, um es zu sehen):

 const getValue1Async = () => { return new Promise(resolve => { setTimeout(resolve, 500, "value1"); }); }; const getValue2Async = () => { return new Promise((resolve, reject) => { setTimeout(reject, 100, "error"); }); }; // This waits the full 500ms before failing, because it waits // on p1, then on p2 (async () => { try { console.time("separate"); const p1 = getValue1Async(); const p2 = getValue2Async(); const value1 = await p1; const value2 = await p2; } catch (e) { console.error(e); } console.timeEnd("separate"); })(); // This fails after just 100ms, because it doesn't wait for p1 // to finish first, it rejects as soon as p2 rejects setTimeout(async () => { try { console.time("Promise.all"); const [value1, value2] = await Promise.all([getValue1Async(), getValue2Async()]); } catch (e) { console.timeEnd("Promise.all", e); } }, 1000); 
 Open the real browser console to see the unhandled rejection error. 

Ich denke, das sollte funktionieren:

  const [value1, value2] = await Promise.all([getValue1Async(),getValue2Async()]);