Fehler
Sprechen wir über Fehler.
Es gibt zwei Arten von Fehlern:
- erwartete Fehler
- unerwartete Fehler
- Off-by-One-Fehler
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 sein
function example(param) {
if (!Array.isArray(param) {
throw new TypeError('"param" should be an array!');
}
...
}
Aus 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.
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 typisierter catch
Konstrukte, sodass Sie zwischen erwarteten und unerwarteten Fehlern unterscheiden können:
C # :
try
{
var example = DoSomething();
}
catch (ExpectedException e)
{
DoSomethingElse(e);
}
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:
try {
let example = doSomething();
} catch (e) {
if (e instanceOf ExpectedError) {
DoSomethingElse(e);
} else {
throw e;
}
}
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:
const user = authenticate();
if (user == null) {
// keep doing stuff
} else {
// handle expected error
}
Alternativ könnte es geschrieben werden als:
try {
const user = authenticate();
// keep doing stuff
} catch (e) {
if (e instanceOf AuthenticationError) {
// handle expected error
} else {
throw e;
}
}
Beides ist akzeptabel.
Versprechen
Sprechen wir über Versprechen.
Versprechen sind eine asynchrone Form von try..catch
. Aufruf new Promise
oder Promise.resolve
Start Ihres try
Codes. Rufen Sie an throw
oder Promise.reject
schickt Sie an den catch
Code.
Promise.resolve(value) // try
.then(doSomething) // try
.then(doSomethingElse) // try
.catch(handleError) // catch
Wenn Sie eine asynchrone Funktion zur Authentifizierung eines Benutzers haben, können Sie diese folgendermaßen schreiben:
authenticate()
.then((user) => {
if (user == null) {
// keep doing stuff
} else {
// handle expected error
}
});
Alternativ könnte es geschrieben werden als:
authenticate()
.then((user) => {
// keep doing stuff
})
.catch((e) => {
if (e instanceOf AuthenticationError) {
// handle expected error
} else {
throw e;
}
});
Beides ist akzeptabel.
Nisten
Sprechen wir über das Verschachteln.
try..catch
kann verschachtelt werden. Ihre authenticate()
Methode hat möglicherweise intern einen try..catch
Block wie:
try {
const credentials = requestCredentialsFromUser();
const user = getUserFromServer(credentials);
} catch (e) {
if (e instanceOf CredentialsError) {
// handle failure to request credentials
} else if (e instanceOf ServerError) {
// handle failure to get data from server
} else {
throw e; // no idea what happened
}
}
Ebenso können Versprechen geschachtelt werden. Ihre asynchrone authenticate()
Methode verwendet möglicherweise intern Versprechen:
requestCredentialsFromUser()
.then(getUserFromServer)
.catch((e) => {
if (e instanceOf CredentialsError) {
// handle failure to request credentials
} else if (e instanceOf ServerError) {
// handle failure to get data from server
} else {
throw e; // no idea what happened
}
});
Also, wie lautet die Antwort?
Ok, ich denke, es ist Zeit für mich, die Frage tatsächlich zu beantworten:
Wird ein Authentifizierungsfehler als etwas angesehen, für das Sie ein Versprechen ablehnen würden?
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 Ihrer then
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.
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
.