Ich habe eine Reihe von Versprechungen, mit denen ich löse Promise.all(arrayOfPromises);
Ich setze die Versprechen-Kette fort. Sieht ungefähr so aus
existingPromiseChain = existingPromiseChain.then(function() {
var arrayOfPromises = state.routes.map(function(route){
return route.handler.promiseHandler();
});
return Promise.all(arrayOfPromises)
});
existingPromiseChain = existingPromiseChain.then(function(arrayResolved) {
// do stuff with my array of resolved promises, eventually ending with a res.send();
});
Ich möchte eine catch-Anweisung hinzufügen, um ein einzelnes Versprechen zu behandeln, falls es fehlerhaft ist. Wenn ich es jedoch versuche, wird Promise.all
der erste gefundene Fehler zurückgegeben (der Rest wird ignoriert), und dann kann ich die Daten aus dem Rest der Versprechen in nicht abrufen das Array (das hat keinen Fehler gemacht).
Ich habe versucht, so etwas wie ..
existingPromiseChain = existingPromiseChain.then(function() {
var arrayOfPromises = state.routes.map(function(route){
return route.handler.promiseHandler()
.then(function(data) {
return data;
})
.catch(function(err) {
return err
});
});
return Promise.all(arrayOfPromises)
});
existingPromiseChain = existingPromiseChain.then(function(arrayResolved) {
// do stuff with my array of resolved promises, eventually ending with a res.send();
});
Das lässt sich aber nicht lösen.
Vielen Dank!
- -
Bearbeiten:
Was die folgenden Antworten sagten, war völlig richtig, der Code brach aus anderen Gründen. Falls jemand interessiert ist, ist dies die Lösung, die ich gefunden habe ...
Node Express-Serverkette
serverSidePromiseChain
.then(function(AppRouter) {
var arrayOfPromises = state.routes.map(function(route) {
return route.async();
});
Promise.all(arrayOfPromises)
.catch(function(err) {
// log that I have an error, return the entire array;
console.log('A promise failed to resolve', err);
return arrayOfPromises;
})
.then(function(arrayOfPromises) {
// full array of resolved promises;
})
};
API-Aufruf (route.async-Aufruf)
return async()
.then(function(result) {
// dispatch a success
return result;
})
.catch(function(err) {
// dispatch a failure and throw error
throw err;
});
Das Setzen des .catch
for Promise.all
vor das .then
scheint den Zweck erfüllt zu haben, Fehler aus den ursprünglichen Versprechungen abzufangen, aber dann das gesamte Array zum nächsten zurückzukehren.then
Vielen Dank!
.then(function(data) { return data; })
kann komplett weggelassen werdenthen
odercatch
Handlern anzeigen und ein Fehler darin ausgelöst wird. Ist das übrigens dieser Knoten?Antworten:
Promise.all
ist alles oder nichts. Es wird aufgelöst, sobald alle Versprechen im Array aufgelöst wurden, oder abgelehnt, sobald einer von ihnen ablehnt. Mit anderen Worten, es wird entweder mit einem Array aller aufgelösten Werte aufgelöst oder mit einem einzigen Fehler zurückgewiesen.Einige Bibliotheken haben einen Namen
Promise.when
, von dem ich verstehe, dass er stattdessen darauf wartet, dass alle Versprechen im Array entweder aufgelöst oder abgelehnt werden, aber ich bin nicht damit vertraut und es ist nicht in ES6.Dein Code
Ich stimme anderen hier zu, dass Ihr Fix funktionieren sollte. Es sollte mit einem Array aufgelöst werden, das eine Mischung aus erfolgreichen Werten und Fehlerobjekten enthalten kann. Es ist ungewöhnlich, Fehlerobjekte im Erfolgspfad zu übergeben, aber wenn Ihr Code sie erwartet, sehe ich kein Problem damit.
Der einzige Grund, warum ich mir vorstellen kann, warum es "nicht aufgelöst" werden kann, ist, dass der Code, den Sie uns nicht anzeigen, fehlschlägt und dass Sie keine Fehlermeldung dazu sehen, weil diese Versprechenskette nicht mit einem Finale beendet wird fangen (soweit du uns sowieso zeigst).
Ich habe mir die Freiheit genommen, die "vorhandene Kette" aus Ihrem Beispiel herauszurechnen und die Kette mit einem Haken zu beenden. Dies mag für Sie nicht richtig sein, aber für Leute, die dies lesen, ist es wichtig, immer entweder Ketten zurückzugeben oder zu beenden, da sonst potenzielle Fehler, sogar Codierungsfehler, versteckt werden (was meiner Meinung nach hier passiert ist):
quelle
Promise.allSettled()
mit angemessener Unterstützung. Siehe Referenz .Promise.all
schlägt fehl, wenn der erste Thread fehlschlägt. Leider laufen alle anderen Threads weiter, bis sie fertig sind. Nichts wird abgebrochen, noch schlimmer: Es gibt keine Möglichkeit, einen Thread abzubrechenPromise
. Was auch immer die Threads tun (und manipulieren), sie ändern weiterhin Zustände und Variablen, sie verwenden CPU, aber am Ende geben sie ihr Ergebnis nicht zurück. Sie müssen sich dessen bewusst sein, um kein Chaos zu erzeugen, z. B. wenn Sie den Anruf wiederholen / wiederholen.NEUE ANTWORT
FUTURE Promise API
quelle
e
aber nicht seinError
. Es kann beispielsweise eine Zeichenfolge sein, wenn jemand sie wie folgt zurückgibtPromise.reject('Service not available')
..then()
und.catch()
.Promise.resolve()
würde den Wert an den ersteren weitergeben, währendPromise.reject()
er an den letzteren weitergegeben wird. Sie können sie beispielsweise in ein Objekt einschließen :p.then(v => ({success: true, value: v})).catch(e => ({success: false, error: e}))
.Um die
Promise.all
Schleife fortzusetzen (auch wenn ein Versprechen abgelehnt wird), habe ich eine Dienstprogrammfunktion geschrieben, die aufgerufen wirdexecuteAllPromises
. Diese Dienstprogrammfunktion gibt ein Objekt mitresults
und zurückerrors
.Die Idee ist, dass alle Versprechen, an die Sie weitergeben,
executeAllPromises
in ein neues Versprechen verpackt werden, das immer aufgelöst wird. Das neue Versprechen wird mit einem Array mit 2 Punkten aufgelöst. Der erste Punkt enthält den Auflösungswert (falls vorhanden) und der zweite Punkt enthält den Fehler (wenn das verpackte Versprechen abgelehnt wird).Als letzter Schritt werden
executeAllPromises
alle Werte der verpackten Versprechen akkumuliert und das endgültige Objekt mit einem Array fürresults
und einem Array für zurückgegebenerrors
.Hier ist der Code:
quelle
ES2020 führt eine neue Methode für den Promise-Typ ein:
Promise.allSettled()
Promise.allSettled gibt Ihnen ein Signal, wenn alle Eingabeversprechen erfüllt sind, was bedeutet, dass sie entweder erfüllt oder abgelehnt werden. Dies ist nützlich, wenn Sie sich nicht für den Stand des Versprechens interessieren, sondern nur wissen möchten, wann die Arbeit erledigt ist, unabhängig davon, ob sie erfolgreich war.
Lesen Sie mehr im v8-Blogbeitrag https://v8.dev/features/promise-combinators
quelle
Wie @jib sagte,
Sie können jedoch bestimmte Versprechen kontrollieren, die "scheitern" dürfen, und wir möchten fortfahren
.then
.Beispielsweise.
quelle
Wenn Sie die q-Bibliothek https://github.com/kriskowal/q verwenden können, verfügt sie über die q.allSettled () -Methode, mit der dieses Problem gelöst werden kann. Sie können jedes Versprechen je nach Status entweder vollständig erfüllen oder ablehnen
quelle
q
) vorschlagen , ist es nützlicher, wenn Sie ein Verwendungsbeispiel für die Frage angeben. Derzeit erklärt Ihre Antwort nicht, wie diese Bibliothek zur Lösung des Problems beitragen kann.Mit Async warten -
Hier gibt eine asynchrone Funktion func1 einen aufgelösten Wert zurück, und func2 gibt einen Fehler aus und gibt in dieser Situation eine Null zurück. Wir können damit umgehen, wie wir wollen, und entsprechend zurückgeben.
Ausgabe ist - ['func1', null]
quelle
Für diejenigen, die ES8 verwenden und hier stolpern, können Sie mit asynchronen Funktionen Folgendes tun :
quelle
Wir können die Ablehnung auf der Ebene der einzelnen Versprechen behandeln. Wenn wir also die Ergebnisse in unserem Ergebnisarray erhalten, ist der abgelehnte Array-Index
undefined
. Wir können mit dieser Situation nach Bedarf umgehen und die verbleibenden Ergebnisse verwenden.Hier habe ich das erste Versprechen abgelehnt, daher ist es undefiniert, aber wir können das Ergebnis des zweiten Versprechens verwenden, das sich auf Index 1 befindet.
quelle
Hast du darüber nachgedacht
Promise.prototype.finally()
?Es scheint so konzipiert zu sein, dass es genau das tut, was Sie wollen - eine Funktion ausführen, sobald alle Versprechen erfüllt (gelöst / abgelehnt) sind, unabhängig davon, ob einige der Versprechen abgelehnt wurden.
Aus der MDN-Dokumentation :
Die
finally()
Methode kann nützlich sein, wenn Sie nach Erfüllung des Versprechens eine Verarbeitung oder Bereinigung durchführen möchten, unabhängig vom Ergebnis.Die
finally()
Methode ist dem Aufruf sehr ähnlich,.then(onFinally, onFinally)
es gibt jedoch einige Unterschiede:Wenn Sie eine Funktion inline erstellen, können Sie sie einmal übergeben, anstatt gezwungen zu sein, sie entweder zweimal zu deklarieren oder eine Variable dafür zu erstellen.
Ein endgültiger Rückruf erhält kein Argument, da es kein zuverlässiges Mittel gibt, um festzustellen, ob das Versprechen erfüllt oder abgelehnt wurde. Dieser Anwendungsfall ist genau dann vorgesehen, wenn Sie sich nicht um den Ablehnungsgrund oder den Erfüllungswert kümmern und daher keine Angabe erforderlich ist.
Im Gegensatz
Promise.resolve(2).then(() => {}, () => {})
(was mit undefined aufgelöst wird)Promise.resolve(2).finally(() => {})
wird mit 2 aufgelöst. Ebenso wird im Gegensatz zuPromise.reject(3).then(() => {}, () => {})
(was mit undefined erfüllt wird)Promise.reject(3).finally(() => {})
mit 3 abgelehnt.== Fallback ==
Wenn Ihre JavaScript-Version dies nicht unterstützt
Promise.prototype.finally()
, können Sie diese Problemumgehung von Jake Archibald verwenden :Promise.all(promises.map(p => p.catch(() => undefined)));
quelle
Promises.allSettled()
es tatsächlich implementiert ist (es wird hier von MDN dokumentiert ),Promises.all.finally()
scheint dann dasselbe zu erreichen. Ich bin im Begriff, es zu versuchen ...allSettled()
.allSettled()
ich weiß , ist es (noch) nirgendwo implementiert, also möchte ich der Realität nicht voraus sein. Ich hatte Erfolg mitPromises.all(myPromiseArray).finally()
, und das passt zu dieser Antwort. Sobald esallSettled()
tatsächlich existiert, könnte ich es testen und herausfinden, wie es tatsächlich funktioniert. Wer weiß bis dahin, was die Browser tatsächlich implementieren werden? Es sei denn, Sie haben aktuelle Informationen zum Gegenteil ...Promise.allSettled
ist nicht in Firefox implementiert, scheint aber in Chrome zu existieren. Nur weil Dokumente sagen, dass es implementiert ist, heißt das nicht, dass es wirklich implementiert ist. Ich werde es nicht so schnell benutzen.Wenn Sie einen Fall haben, in dem Sie sich nicht besonders um die Werte der aufgelösten Versprechen kümmern, wenn es einen Fehler gibt, Sie aber dennoch möchten, dass sie ausgeführt werden, können Sie so etwas tun, das mit den Versprechen wie gewohnt gelöst wird, wenn Sie alle haben Erfolg und lehnen die fehlgeschlagenen Versprechen ab, wenn einer von ihnen versagt:
quelle
Sie können Ihre Versprechen-Rückgabefunktionen jederzeit so verpacken, dass sie Fehler auffangen und stattdessen einen vereinbarten Wert (z. B. error.message) zurückgeben, sodass die Ausnahme nicht bis zur Funktion Promise.all reicht und diese deaktiviert.
quelle
Ich habe einen Weg gefunden (Problemumgehung), um dies zu tun, ohne es zu synchronisieren.
Wie bereits erwähnt,
Promise.all
ist alles von keinem.Also ... Verwenden Sie ein beiliegendes Versprechen, um die Entschlossenheit zu fangen und zu erzwingen.
quelle
Sie müssen wissen, wie Sie einen Fehler in Ihren Ergebnissen identifizieren können. Wenn Sie keinen erwarteten Standardfehler haben, schlage ich vor, dass Sie für jeden Fehler im catch-Block eine Transformation ausführen, die ihn in Ihren Ergebnissen identifizierbar macht.
quelle
Nicht der beste Weg zum Fehlerprotokoll, aber Sie können immer alles auf ein Array für das VersprechenAll setzen und die resultierenden Ergebnisse in neuen Variablen speichern.
Wenn Sie graphQL verwenden, müssen Sie die Antwort unabhängig davon nachbearbeiten. Wenn die richtige Referenz nicht gefunden wird, stürzt die App ab und wird eingegrenzt, wo das Problem liegt
quelle
So
Promise.all
soll es funktionieren. Wenn ein einzelnes Versprechenreject()
vorliegt, schlägt die gesamte Methode sofort fehl.Es gibt Anwendungsfälle, in denen man möglicherweise zulassen möchte,
Promise.all
dass Versprechen scheitern. Verwenden Sie dazu einfach keinereject()
Aussagen in Ihrem Versprechen. Um jedoch sicherzustellen, dass Ihre App / Ihr Skript nicht einfriert, falls ein einzelnes zugrunde liegendes Versprechen keine Antwort erhält, müssen Sie eine Zeitüberschreitung festlegen.quelle
reject()
ist in Ordnung, Ihr Versprechen nicht zu verwenden , aber was ist, wenn Sie die Versprechen einer anderen Bibliothek verwenden müssen?Ich habe eine npm-Bibliothek geschrieben, um dieses Problem noch schöner zu lösen. https://github.com/wenshin/promiseallend
Installieren
2017-02-25 neue API, es ist nicht Bruch Versprechen Prinzipien
———————————————————————————————————
Alte schlechte API, benutze es nicht!
quelle
Promise.all
. Aber es werden alle Daten und Fehler jedes Versprechens gesammelt. Es unterstützt auch die Objekteingabe, es ist kein Punkt. Nachdem ich alle Daten und Fehler gesammelt habe, überschreibe ich diepromise.then
Methode, um mit den registrierten Rückrufen umzugehen, die abgelehnt und erfüllt sind. Für Details können Sie den Code sehenonFulfilled
undonRejected
Handler auf, die an übergeben werdenthen
?fulfilled
undrejected
. Aber wirklich, es verursacht ein schweres Problem, mit allen Versprechen Anwendungsfällen normal kompatibel zu sein, wieonFulfilled
undonRejected
alle zurückPromise.reject()
oderPromise.resolve()
. Bisher ist mir nicht klar, wie ich es lösen soll. Hat jemand eine bessere Idee? Die beste Antwort für den Moment ist, dass möglicherweise keine Daten und Fehler in der Browserumgebung gefiltert werden können.