Ich bin noch ziemlich neu in Versprechungen und benutze derzeit Bluebird, aber ich habe ein Szenario, in dem ich nicht ganz sicher bin, wie ich am besten damit umgehen soll.
So habe ich zum Beispiel eine Versprechen-Kette in einer Express-App wie folgt:
repository.Query(getAccountByIdQuery)
.catch(function(error){
res.status(404).send({ error: "No account found with this Id" });
})
.then(convertDocumentToModel)
.then(verifyOldPassword)
.catch(function(error) {
res.status(406).send({ OldPassword: error });
})
.then(changePassword)
.then(function(){
res.status(200).send();
})
.catch(function(error){
console.log(error);
res.status(500).send({ error: "Unable to change password" });
});
Das Verhalten, nach dem ich bin, ist also:
- Geht, um Konto durch ID zu erhalten
- Wenn es zu diesem Zeitpunkt eine Ablehnung gibt, bombardieren Sie und geben Sie einen Fehler zurück
- Wenn kein Fehler auftritt, konvertieren Sie das zurückgegebene Dokument in ein Modell
- Überprüfen Sie das Kennwort mit dem Datenbankdokument
- Wenn die Passwörter nicht übereinstimmen, bombardieren Sie und geben Sie einen anderen Fehler zurück
- Wenn kein Fehler vorliegt, ändern Sie die Passwörter
- Dann kehren Sie zum Erfolg zurück
- Wenn etwas anderes schief gelaufen ist, geben Sie eine 500 zurück
Derzeit scheinen Fänge die Verkettung nicht zu stoppen, und das macht Sinn. Ich frage mich daher, ob es für mich eine Möglichkeit gibt, die Kette aufgrund der Fehler an einem bestimmten Punkt anzuhalten, oder ob es einen besseren Weg gibt dies zu strukturieren, um irgendeine Form von Verzweigungsverhalten zu erhalten, wie es einen Fall von gibt if X do Y else Z
.
Jede Hilfe wäre großartig.
javascript
node.js
promise
bluebird
Grofit
quelle
quelle
Antworten:
Dieses Verhalten ist genau wie ein synchroner Wurf:
Das ist die Hälfte des Punktes
.catch
- um Fehler beheben zu können. Es kann wünschenswert sein, erneut zu werfen, um zu signalisieren, dass der Zustand immer noch ein Fehler ist:Dies allein funktioniert in Ihrem Fall jedoch nicht, da der Fehler von einem späteren Handler abgefangen wird. Das eigentliche Problem hierbei ist, dass verallgemeinerte "HANDLE ANYTHING" -Fehlerbehandlungsroutinen im Allgemeinen eine schlechte Praxis sind und in anderen Programmiersprachen und Ökosystemen äußerst verpönt sind. Aus diesem Grund bietet Bluebird typisierte und prädikative Fänge an.
Der zusätzliche Vorteil besteht darin, dass Ihre Geschäftslogik den Anforderungs- / Antwortzyklus überhaupt nicht kennen muss (und sollte). Es liegt nicht in der Verantwortung der Abfrage, zu entscheiden, welchen HTTP-Status und Fehler der Client erhält. Später, wenn Ihre App wächst, möchten Sie möglicherweise die Geschäftslogik (wie Sie Ihre Datenbank abfragen und wie Sie Ihre Daten verarbeiten) von dem trennen, was Sie an den Client senden (Welcher http-Statuscode, welcher Text und welche Antwort).
So würde ich Ihren Code schreiben.
Zuerst würde ich
.Query
eine werfenNoSuchAccountError
, ich würde es unterordnen, vonPromise.OperationalError
der Bluebird bereits bereitstellt. Wenn Sie sich nicht sicher sind, wie Sie einen Fehler unterordnen sollen, lassen Sie es mich wissen.Ich würde es zusätzlich unterordnen
AuthenticationError
und dann etwas tun wie:Wie Sie sehen können, ist es sehr sauber und Sie können den Text wie eine Bedienungsanleitung lesen, was dabei passiert. Es ist auch von der Anfrage / Antwort getrennt.
Jetzt würde ich es vom Routen-Handler als solches bezeichnen:
Auf diese Weise befindet sich die Logik an einem Ort und die Entscheidung, wie mit Fehlern für den Client umgegangen werden soll, ist an einem Ort und sie überlagern sich nicht.
quelle
.catch(someSpecificError)
für einen bestimmten Fehler darin besteht, dass Sie einen bestimmten Fehlertyp (der harmlos ist) abfangen, damit umgehen und den folgenden Ablauf fortsetzen möchten. Zum Beispiel habe ich einen Startcode, der eine Reihe von Aufgaben hat. Das erste ist, die Konfigurationsdatei von der Festplatte zu lesen, aber wenn diese Konfigurationsdatei fehlschlägt, ist dies ein OK-Fehler (das Programm hat Standardeinstellungen eingebaut), damit ich diesen spezifischen Fehler behandeln und den Rest des Ablaufs fortsetzen kann. Es kann auch besser sein, die Reinigung erst später zu verlassen.instanceof
weiterkommen und alles manuell erledigen können..catch
funktioniert wie dietry-catch
Anweisung, was bedeutet, dass Sie am Ende nur einen Fang benötigen:quelle
Nein. Sie können eine Kette nicht wirklich "beenden", es sei denn, Sie lösen eine Ausnahme aus, die bis zu ihrem Ende sprudelt. Siehe dazu Benjamin Gruenbaums Antwort .
Eine Ableitung seines Musters wäre nicht die Unterscheidung von Fehlertypen, sondern die Verwendung von Fehlern
statusCode
undbody
Feldern, die von einem einzelnen generischen.catch
Handler gesendet werden können . Abhängig von Ihrer Anwendungsstruktur ist seine Lösung möglicherweise sauberer.Ja, Sie können mit Versprechungen verzweigen . Dies bedeutet jedoch, die Kette zu verlassen und zum Verschachteln zurückzukehren, genau wie Sie es in einer verschachtelten if-else- oder try-catch-Anweisung tun würden:
quelle
Ich habe so gemacht:
Sie verlassen Ihren Fang am Ende. Und werfen Sie einfach einen Fehler, wenn es in der Mitte Ihrer Kette passiert.
Ihre anderen Funktionen würden wahrscheinlich ungefähr so aussehen:
quelle
Wahrscheinlich etwas spät zur Party, aber es ist möglich,
.catch
wie hier gezeigt zu nisten :Mozilla Developer Network - Versprechen verwenden
Bearbeiten: Ich habe dies eingereicht, weil es die angeforderte Funktionalität im Allgemeinen bietet. In diesem speziellen Fall ist dies jedoch nicht der Fall. Denn wie bereits von anderen ausführlich erklärt,
.catch
soll der Fehler behoben werden. Sie können beispielsweise keine Antwort in mehreren.catch
Rückrufen an den Client senden, da dies in diesem Fall durch a.catch
ohne explizitereturn
Auflösung behoben wird. Dies führt dazuundefined
, dass das Verfahren.then
ausgelöst wird, obwohl Ihre Kette nicht wirklich aufgelöst ist, wodurch möglicherweise eine Folge.catch
ausgelöst und gesendet wird eine weitere Antwort an den Client, die einen Fehler verursacht und wahrscheinlichUnhandledPromiseRejection
Ihren Weg wirft . Ich hoffe, dieser verschlungene Satz hat für Sie einen Sinn ergeben.quelle
Anstelle von
.then().catch()...
dir kann.then(resolveFunc, rejectFunc)
. Diese Versprechenskette wäre besser, wenn Sie die Dinge auf dem Weg erledigen würden. Hier ist, wie ich es umschreiben würde:Hinweis: Dies
if (error != null)
ist ein Hack, um mit dem neuesten Fehler zu interagieren.quelle
Ich denke, Benjamin Gruenbaums Antwort oben ist die beste Lösung für eine komplexe Logiksequenz, aber hier ist meine Alternative für einfachere Situationen. Ich benutze nur ein
errorEncountered
Flag zusammen mitreturn Promise.reject()
, um nachfolgendethen
odercatch
Anweisungen zu überspringen . So würde es aussehen:Wenn Sie mehr als zwei Then / Catch-Paare haben, sollten Sie wahrscheinlich die Lösung von Benjamin Gruenbaum verwenden. Dies funktioniert jedoch für eine einfache Einrichtung.
Beachten Sie, dass die endgültige
catch
nur hatreturn;
stattreturn Promise.reject();
, weil es keine spätere ist ,then
dass wir überspringen müssen, und es würde als nicht behandelte Versprechen Ablehnung zählen, die Knoten nicht wie. Wie oben geschrieben, wird das Finalecatch
ein friedlich gelöstes Versprechen zurückgeben.quelle