Nehmen wir an, ich lasse diese Funktion authentifizieren, die ein Versprechen zurückgibt. Das Versprechen löst sich dann mit dem Ergebnis auf. Falsch und wahr sind erwartete Ergebnisse, wie ich es sehe, und Ablehnungen sollten nur in einem Fehlerfall auftreten. Oder wird ein Authentifizierungsfehler als etwas angesehen, für das Sie ein Versprechen ablehnen würden?
javascript
Mathieu Bertin
quelle
quelle
reject
und nicht falsch zurück, aber wenn Sie den Wert erwarten eine seinBool
, dann Sie waren erfolgreich , und Sie sollten mit dem Bool unabhängig vom Wert lösen. Versprechungen sind eine Art Stellvertreter für Werte - sie speichern den zurückgegebenen Wert, also sollten Sie nur dann, wenn der Wert nicht erhalten werden konntereject
. Ansonsten solltest duresolve
.false
oder Auslösen einer Ausnahme behandeln?then
wenn der Server antwortet - auch wenn ein Fehlercode zurückgegeben wird - und Sie müssen das überprüfenresponse.ok
. Dercatch
Handler wird nur bei unerwarteten Fehlern ausgelöst .Antworten:
Gute Frage! Es gibt keine harte Antwort. Dies hängt davon ab, was Sie an diesem bestimmten Punkt des Flusses für außergewöhnlich halten .
A zurückzuweisen
Promise
ist dasselbe wie eine Ausnahme auszulösen . Nicht alle unerwünschten Ergebnisse sind außergewöhnlich , die Folge von Fehlern . Sie könnten Ihren Fall in beide Richtungen argumentieren:Fehlgeschlagene Authentifizierung sollte
reject
dasPromise
, weil der Anrufer ein erwartetesUser
Objekt im Gegenzug, und alles anderes ist eine Ausnahme von dieser Strömung.Fehlgeschlagene Authentifizierung sollte
resolve
dasPromise
, wenn auch zunull
, da die falschen Zugangsdaten einzugeben nicht wirklich eine ist Ausnahmefall, und der Anrufer sollte der Fluss immer ergibt eine nicht erwartenUser
.Beachten Sie, dass ich das Problem von der Seite des Anrufers aus betrachte . Erwartet der Anrufer im Informationsfluss, dass seine Aktionen zu
User
einem Fehler führen (und alles andere ist ein Fehler), oder ist es sinnvoll, dass dieser bestimmte Anrufer mit anderen Ergebnissen umgeht?In einem mehrschichtigen System kann sich die Antwort ändern, wenn die Daten durch die Schichten fließen. Beispielsweise:
null
Benutzer aufgelöst wird.Dieses 4-Punkte-Beispiel ist offensichtlich kompliziert, zeigt aber 2 Punkte:
Also nochmal, keine harte Antwort. Zeit zum Nachdenken und Gestalten!
quelle
Promises haben also eine nette Eigenschaft, dass sie JS aus funktionalen Sprachen holen. Das heißt, sie implementieren tatsächlich diesen
Either
Typkonstruktor, der zwei andere Typen, denLeft
Typ und denRight
Typ, zusammenhält, indem sie die Logik zwingen, entweder den einen oder den anderen Zweig zu nehmen Ast.Jetzt bemerken Sie tatsächlich, dass der Typ auf der linken Seite für Versprechungen mehrdeutig ist; Sie können mit allem ablehnen. Dies ist wahr, weil JS schwach getippt ist, aber Sie sollten vorsichtig sein, wenn Sie defensiv programmieren.
Der Grund dafür ist, dass JS
throw
Anweisungen aus dem Code zum Umgang mit Versprechungen übernimmt und sie auch in diesen Code einbindetLeft
. Technisch gesehen können Sie in JSthrow
alles, einschließlich true / false oder eine Zeichenfolge oder eine Zahl, aber JavaScript-Code wirft auch Dinge ohnethrow
(wenn Sie versuchen, auf Eigenschaften für Nullen zuzugreifen), und es gibt eine festgelegte API für diese (dasError
Objekt). . Wenn Sie sich also dem Fangen nähern, ist es normalerweise schön anzunehmen, dass diese FehlerError
Objekte sind. Und da sich diereject
für das Versprechen bei Fehlern aus einem der oben genannten Fehler zusammenballen, möchten Sie im Allgemeinen nurthrow
andere Fehler, damit Ihrecatch
Aussage eine einfache, konsistente Logik hat.Deshalb , obwohl Sie können eine if-Bedingung in Ihrem setzen
catch
und sucht falsche Fehler, in diesem Fall die Wahrheit Fall trivial ist,Sie werden wahrscheinlich die logische Struktur eines einfacheren Booleschen bevorzugen, zumindest für das, was unmittelbar aus dem Authentifikator hervorgeht:
Tatsächlich besteht die nächste Ebene der Authentifizierungslogik wahrscheinlich darin, eine Art
User
Objekt zurückzugeben, das den authentifizierten Benutzer enthält.und das ist mehr oder weniger das, was ich erwarten würde: return
null
für den Fall, dass der Benutzer nicht definiert ist, andernfalls return{user_id: <number>, permission_to_launch_missiles: <boolean>}
. Ich würde erwarten , dass der allgemeine Fall nicht in salvageable protokolliert ist, zum Beispiel , wenn wir in einer Art „Demo zu neuen Kunden“ -Modus sind, und soll mit Bugs nicht gemischt sein , wo ich zufällig genannt ,object.doStuff()
wennobject.doStuff
warundefined
.Nachdem dies gesagt wurde, möchten Sie möglicherweise eine
NotLoggedIn
oder einePermissionError
Ausnahme definieren, die von abgeleitet istError
. Dann wollen Sie in den Dingen, die es wirklich brauchen, schreiben:quelle
Fehler
Sprechen wir über Fehler.
Es gibt zwei Arten von Fehlern:
Erwartete Fehler
Erwartete Fehler sind Zustände, in denen das Falsche passiert, aber Sie wissen, dass dies möglich ist.
Dies sind Dinge wie Benutzereingaben oder Serveranforderungen. Sie wissen, dass der Benutzer möglicherweise einen Fehler gemacht hat oder der Server heruntergefahren ist. Schreiben Sie daher einen Überprüfungscode, um sicherzustellen, dass das Programm erneut nach Eingaben fragt oder eine Meldung anzeigt, oder was auch immer für ein anderes Verhalten angemessen ist.
Diese können bei der Bearbeitung wiederhergestellt werden. Wenn sie unbehandelt bleiben, werden sie zu unerwarteten Fehlern.
Unerwartete Fehler
Unerwartete Fehler (Bugs) sind Zustände, in denen das Falsche passiert, weil der Code falsch ist. Sie wissen, dass sie irgendwann eintreten werden, aber es gibt keine Möglichkeit zu wissen, wo und wie Sie mit ihnen umgehen sollen, da sie per Definition unerwartet sind.
Dies sind Dinge wie Syntax- und Logikfehler. Möglicherweise haben Sie einen Tippfehler in Ihrem Code. Möglicherweise haben Sie eine Funktion mit den falschen Parametern aufgerufen. Diese können normalerweise nicht wiederhergestellt werden.
try..catch
Lass uns darüber reden
try..catch
.Wird in JavaScript
throw
nicht häufig verwendet. Wenn Sie sich nach Beispielen im Code umschauen, werden sie selten und in der Regel nach dem Muster von strukturiert seinAus diesem Grund sind
try..catch
Blöcke auch für den Steuerungsfluss nicht allzu häufig. Es ist normalerweise ziemlich einfach, einige Prüfungen hinzuzufügen, bevor Methoden aufgerufen werden, um erwartete Fehler zu vermeiden.JavaScript-Umgebungen sind auch ziemlich nachsichtig, so dass auch unerwartete Fehler oft unbemerkt bleiben.
C # :try..catch
muss nicht ungewöhnlich sein. Es gibt einige nützliche Anwendungsfälle, die in Sprachen wie Java und C # häufiger vorkommen. Java und C # haben den Vorteil typisiertercatch
Konstrukte, sodass Sie zwischen erwarteten und unerwarteten Fehlern unterscheiden können:In diesem Beispiel können andere unerwartete Ausnahmen auftreten und an anderer Stelle behandelt werden (z. B. durch Protokollieren und Schließen des Programms).
In JavaScript kann dieses Konstrukt repliziert werden über:
Nicht so elegant, was ein Grund dafür ist, dass es ungewöhnlich ist.
Funktionen
Sprechen wir über Funktionen.
Wenn Sie das Prinzip der Einzelverantwortung anwenden , sollte jede Klasse und Funktion einem bestimmten Zweck dienen.
Zum Beispiel
authenticate()
könnte ein Benutzer authentifizieren.Dies könnte geschrieben werden als:
Alternativ könnte es geschrieben werden als:
Beides ist akzeptabel.
Versprechen
Sprechen wir über Versprechen.
Versprechen sind eine asynchrone Form von
try..catch
. Aufrufnew Promise
oderPromise.resolve
Start Ihrestry
Codes. Rufen Sie anthrow
oderPromise.reject
schickt Sie an dencatch
Code.Wenn Sie eine asynchrone Funktion zur Authentifizierung eines Benutzers haben, können Sie diese folgendermaßen schreiben:
Alternativ könnte es geschrieben werden als:
Beides ist akzeptabel.
Nisten
Sprechen wir über das Verschachteln.
try..catch
kann verschachtelt werden. Ihreauthenticate()
Methode hat möglicherweise intern einentry..catch
Block wie:Ebenso können Versprechen geschachtelt werden. Ihre asynchrone
authenticate()
Methode verwendet möglicherweise intern Versprechen:Also, wie lautet die Antwort?
Ok, ich denke, es ist Zeit für mich, die Frage tatsächlich zu beantworten:
Die einfachste Antwort, die ich geben kann, ist, dass Sie ein Versprechen überall ablehnen sollten, wo Sie sonst
throw
eine Ausnahme wünschen würden, wenn es synchroner Code wäre.Wenn Ihr Kontrollfluss durch einige
if
Überprüfungen Ihrerthen
Aussagen einfacher ist , müssen Sie ein Versprechen nicht ablehnen.Wenn Ihr Kontrollfluss einfacher ist, indem Sie ein Versprechen ablehnen und dann in Ihrem Fehlerbehandlungscode nach Fehlertypen suchen, tun Sie dies stattdessen.
quelle
Ich habe den Zweig "Zurückweisen" eines Versprechens verwendet, um die Aktion "Abbrechen" von Dialogfeldern der jQuery-Benutzeroberfläche darzustellen. Dies erschien natürlicher als die Verwendung des Zweigs "Auflösen", nicht zuletzt, weil in einem Dialogfeld häufig mehrere "Schließen" -Optionen vorhanden sind.
quelle
Die Abwicklung eines Versprechens ist mehr oder weniger eine "wenn" Bedingung. Es liegt an Ihnen, ob Sie das Problem lösen oder ablehnen möchten, wenn die Authentifizierung fehlgeschlagen ist.
quelle
try..catch
, nichtif
.try...catch
und einfach sagen, dass Sie unabhängig vom empfangenen Wert eine Lösung finden sollten, wenn Sie ein Ergebnis erzielen konnten. Andernfalls sollten Sie dies ablehnen.try { if (!doSomething()) throw whatever; doSomethingElse() } catch { ... }
ist vollkommen in Ordnung, aber das Konstrukt, das aPromise
darstellt, ist dertry..catch
Teil, nicht derif
Teil.doSomething()
fehlschlägt, es auslöst, aber wenn nicht, könnte es den Wert enthalten, den Sie benötigen (Ihrif
obiges ist etwas verwirrend, da es nicht Teil Ihrer Idee hier ist :)). Sie sollten nur ablehnen, wenn es einen Grund zum Werfen gibt (in der Analogie), also wenn der Test fehlgeschlagen ist. Wenn der Test erfolgreich war, sollten Sie immer entscheiden, ob der Wert positiv ist, oder?