try-catch in Javascript… ist das nicht eine gute Praxis?

69

In Javascript ist ein Try-Catch- Block vorgesehen . Obwohl es in Java oder einer anderen Sprache obligatorisch ist, Fehler zu behandeln, sehe ich niemanden, der sie in größerem Umfang in Javascript verwendet. Ist es nicht eine gute Übung oder brauchen wir sie nur nicht in Javascript?

akp
quelle
2
While in java or *any other language* it is mandatory to have error handling...- Nicht wirklich. Java, ja, aber es gibt viele Sprachen, die nicht auf Try-Catch bestehen (wie C #).
Jim G.
Dies liegt daran, dass Sie sie nicht in einer asynchronen Umgebung verwenden können. Ich benutze sie oft, indem ich Code von einer niedrigeren Abstraktionsebene synchronisiere, zum Beispiel indem ich etwas in etwas
umwandle
Ich wette, Sie sehen mehr Try-Catchs im serverseitigen Code als im clientseitigen Code. Der Großteil des Codes auf der Client-Seite, mit dem Sie vertraut sind, macht nichts Wichtiges. Ich würde wetten, dass das Minimieren von KB in der Pipeline wichtiger ist als die Wiederherstellung nach jedem Fehler - in den meisten Anwendungen und unter den Umständen auf der Browserseite.
Svidgen
Es gibt noch einen anderen Weg, um zu vermeiden, dass Sie versuchen, vielleicht zu fangen, und entweder (Monaden) hatten wir einen Web-Scrapper in Node geschrieben. Wir konnten den gesamten Versuchsfang damit entfernen.
User93

Antworten:

66

Man sollte throwFehler vermeiden , um Fehlerbedingungen in Anwendungen weiterzugeben.

Die throwAussage sollte nur verwendet werden "Denn dies sollte niemals passieren, abstürzen und brennen. Nicht elegant in irgendeiner Weise erholen."

try catch Wird jedoch in Situationen verwendet, in denen Hostobjekte oder ECMAScript Fehler auslösen können.

Beispiel:

var json
try {
    json = JSON.parse(input)
} catch (e) {
    // invalid json input, set to null
    json = null
}

In der node.js- Community wird empfohlen , Fehler in Rückrufen (da Fehler nur bei asynchronen Operationen auftreten) als erstes Argument weiterzugeben

fs.readFile(uri, function (err, fileData) {
    if (err) {
        // handle
        // A. give the error to someone else
        return callback(err)
        // B. recover logic
        return recoverElegantly(err)
        // C. Crash and burn
        throw err
    }
    // success case, handle nicely
})

Es gibt auch andere Probleme, wie Try / Catch ist sehr teuer und es ist hässlich und es funktioniert einfach nicht mit asynchronen Operationen.

Da synchrone Vorgänge keinen Fehler auslösen sollten und bei asynchronen Vorgängen nicht funktionieren, verwendet niemand try catch, außer für Fehler, die von Hostobjekten oder ECMAScript ausgelöst werden

Raynos
quelle
2
Ich würde nicht sagen, dass niemand try catch benutzt, es ist in den meisten Fällen nur das falsche Werkzeug für den Job. Wenn es wirklich außergewöhnliche Umstände gibt, kann es sich lohnen, einen zu werfen Error, aber es gibt nur wenige und weit voneinander entfernt.
zzzzBov
7
@zzzzBov Es ist nichts Falsches daran, Fehler für Fall C, Absturz und Brand zu werfen. Ich denke einfach nicht, dass Sie Fehler abfangen und wiederherstellen sollten. Zum Beispiel document.getElementByIdwird nicht geworfen, wenn das Element nicht vorhanden ist, sondern nur zurückgegeben null. Das gleiche kann für fast alle Fälle getan werden
Raynos
4
@Raynos, das Werfen von einer Synchronisierungsfunktion ist völlig akzeptabel und in diesem Anwendungsfall sinnvoll. Das Zurücksenden von Fehlern an den Rückruf erfolgt asynchron, während das Zurücksenden von Fehlern synchronisiert wird.
Sbartell
@Raynos haben gute Ratschläge zur Vermeidung von Fehlern / Ausnahmen bei der Flusskontrolle auf der Clientseite (Nicht-Knoten-Umgebung)? Ich habe diesen Beitrag auf StackOverflow gefunden , aber er ist hauptsächlich auf Java ausgerichtet
am
@ b.long einfach. Wirf niemals Fehler. Problem gelöst.
Raynos
32

Try / catch in Javascript ist aufgrund der asynchronen Natur von Javascript nicht so kugelsicher wie in anderen Sprachen. Betrachten Sie dieses Snippet:

try {
    setTimeout(function() {
        do_something_that_throws();
    }, 1000);
}
catch (e) {
    alert("You won't see this!");
}

Das Problem ist, dass der Kontrollfluss den tryBlock verlässt , bevor er do_something_that_throws()ausgeführt wird, sodass der Fehler, der im Callback ausgelöst wird, niemals abgefangen wird.

Try / catch ist daher in vielen Fällen grundsätzlich unangemessen und es ist nicht immer offensichtlich, ob Code asynchron ausgeführt wird oder nicht. Glücklicherweise bietet Javascript mit seiner eigentümlichen Singlethread-Asynchronous-Callback-Sprache und seiner Unterstützung für tatsächliche Abschlüsse eine elegante Alternative: Fehlerbehandlung im Continuation-Passing-Stil. Übergeben Sie einfach die richtige Antwort auf einen Fehler als Funktion, z.

setTimeout(function () {
    do_something_that_calls_err(function(err) {
        alert("Something went wrong, namely this: " + err);
    }),
    1000);
tdammers
quelle
5
es ist auch in anderen Sprachen nicht kugelsicher. Portieren Sie diesen Code in eine Sprache, die asynchrone Rückrufe unterstützt, und es wird auch fehlschlagen.
Raynos
2
@ Raynos: Sie haben recht; Andere Sprachen (oder vielmehr ihre unterstützenden Kulturen) kaufen dies jedoch nicht so stark in die Asynchronous-Callback-Sprache ein wie Javascript, und aufgrund der Multithread-Natur der meisten anderen Umgebungen sind die Mängel von try / catch offensichtlicher und Umgeben von vielen anderen Vorbehalten, gehen Menschen in Situationen mit mehreren Threads / asynchronen Rückrufen auf natürliche Weise vorsichtig vor und sind sich potenzieller Gefahren bewusst.
Tdammers
Liegt das wirklich an der "Asynchronität" von JavaScript? So weit ich sehen kann, könnte Try / Catch theoretisch dazu gebracht werden, lexikalisch so zu arbeiten, wie Identifikatoren lexikalisch geschlossen sind. In JavaScript funktioniert das einfach nicht so.
Brian Gordon
2
In node.js> = 0.8 ist es erwähnenswert, dass es möglich ist, asynchron zu versuchen / zu fangen, siehe meine Frage stackoverflow.com/questions/14301839/…
Benjamin Gruenbaum
Ist die einzige Alternative zum synchronen Try-Catch der asynchrone Weitergabestil?
CMCDragonkai
23

Viele dieser Antworten sind etwas alt und berücksichtigen nicht die neuen ES7-Funktionen asyncund await.

Mit async/ können awaitSie jetzt einen asynchronen Kontrollfluss erhalten, wie Sie möchten:

async function email(address) {
  try {
    // Do something asynchronous that may throw...
    await sendEmail({ to: address, from: '[email protected]`, subject: 'Hello' })
  } catch(err) {
    if (err instanceof SomeCustomError) {
      elegantlyHandleError(err)
    } else {
      throw err
    } 
  }
})

Erfahren Sie mehr über async/ awaithier . Du kannst async/ awaitjetzt mit babel .

Dana Woodman
quelle
Aber es ist ähnlich wie bei einem synchronen Code
Atul Agrawal
@AtulAgrawal ja, das ist der Punkt. Mit Async / await können Sie synchronen Async-Code schreiben, um die "Rückruf-Hölle" und die Verkettung vieler Versprechen zu vermeiden. Meiner Meinung nach ist es eine sehr unterhaltsame Art, asynchronen Code zu schreiben
Dana Woodman,
also, was ist der Vorteil der Verwendung von Javascript, wenn wir asynchronen Code synchron machen. weil die meisten Leute Javascript wegen seiner asynchronen Natur verwenden
Atul Agrawal
2
@AtulAgrawal Sie erhalten das Beste aus beiden Welten - Sie genießen die asynchrone Natur der Sprache (da der obige Code weiterhin asynchron ausgeführt wird - wodurch der Thread und alle Elemente freigegeben werden) und Sie die Vorteile eines programmiererfreundlicheren Codierungsstils nutzen können. Es ist jedoch nicht ohne Probleme ...
ZenMaster
15

try-catch in Javascript ist genauso gültig und nützlich wie in jeder anderen Sprache, die es implementiert. Es gibt einen Hauptgrund, warum es in Javascript nicht so oft verwendet wird wie in anderen Sprachen. Aus demselben Grund wird Javascript als eine hässliche Skriptsprache angesehen. Aus demselben Grund denken die Leute, Javascript-Programmierer seien keine echten Programmierer:

  • Javascript ist eine unglaublich zugängliche und allgegenwärtige Sprache

Die bloße Tatsache, dass so viele Menschen Javascript ausgesetzt sind (aufgrund der einzigen von Browsern unterstützten Sprache), bedeutet, dass Sie viele unprofessionelle Codes haben. Natürlich gibt es auch viele kleinere Gründe:

  • Einige Dinge in Javascript sind asynchron und daher nicht in der catchLage (asynchrones Zeug)
  • Es wurde viel überstrapaziert darüber, wie Try-Catch einen enormen Performance-Erfolg hat. Es hat ein wenig Leistungseinbußen , aber für die meisten Codes lohnt es sich.
  • Javascript wurde (leider) so implementiert, dass Fehler oft unbemerkt ignoriert werden (zB automatisch Zeichenketten in Zahlen ändern)

Unabhängig davon sollte try-catch verwendet werden, aber Sie sollten natürlich lernen, wie man sie richtig verwendet - wie alles andere in der Programmierung.

user250878
quelle
3
Und warum hast du dich jemals abgewählt, oh stiller Downvoter?
user250878
Einverstanden. Ich denke, die akzeptierte Antwort ist im Allgemeinen richtig, aber es gibt gute Gründe, try-catch zu verwenden und sogar zu werfen, außer wenn es sich um native Objekte handelt. Wenn ein Fehler ausgelöst und nicht an einen Rückruf übergeben wird, wird die weitere Ausführung angehalten und der Stapel wird zum ersten Block hochgesprungen, der den Fehler nicht verarbeiten kann. Dies ist ein großer Vorteil und für Synchronoperationen, insbesondere wenn es sich um tiefe Verschachtelungen handelt, sehr sinnvoll. Es scheint verrückt zu sein, Ausnahmen als "schlecht" zu bezeichnen (außer aus den offensichtlichen Gründen) - sie sind tatsächlich ein sehr nützliches Werkzeug mit einer einzigartigen "Kraft".
Semikolon
2
Haben Sie sich jemals die Zeit genommen, den Quellcode von beispielsweise jQuery zu lesen? Es gibt kaum einen Versuch, dies zu versuchen, außer in genau den Szenarien, die in der akzeptierten Antwort erwähnt wurden: Features zu erkennen und native / Host-Objekte zu verwenden, die Fehler auslösen. Code aufzurufen, der nicht viel try-catch verwendet (wie jQuery), erscheint unprofessionell. Um ehrlich zu sein, denke ich, dass gerade neue Javascript-Programmierer aus Java dazu neigen, Sprachfunktionen wie Try-Catch zu stark zu nutzen.
Stijn de Witt,
6

Ich glaube, dass ein Großteil des Grundes, der try..catchin JavaScript selten vorkommt, darin besteht, dass die Sprache eine ziemlich hohe Fehlertoleranz aufweist. Die überwiegende Mehrheit der Situationen kann mithilfe von Codeüberprüfungen, guten Standardeinstellungen und asynchronen Ereignissen bewältigt werden. In einigen Fällen können Sie Probleme vermeiden, indem Sie einfach ein Muster verwenden:

function Foo() {
    //this may or may not be called as a constructor!!
    //could accidentally overwrite properties on window
}

function Bar() {
    if (!(this instanceof Bar)) {
        return new Bar();
    }
    //this will only work on Bar objects, and wont impact window
}

Einige der Hauptprobleme in anderen Sprachen, die zum Auftreten von Ausnahmen führen, sind in JS einfach nicht vorhanden. Typguss wird in den meisten Fällen nicht benötigt. Die bevorzugte Methode ist in der Regel die Funktionsprüfung (Erzwingen einer bestimmten Schnittstelle):

function doFoo(arg) {
    if (arg.foo) {
        arg.foo();
    } else {
        Bar.prototype.foo.call(arg);
    }
}

Mit der Hinzufügung von async/ awaitzur Sprache try..catchwird immer mehr verbreitet. Da Versprechungen die asynchrone Form von sind try..catch, ist es sinnvoll, Folgendes zu erwarten:

doSomething().then(
  doSomethingWithResult,
  doSomethingWithError
)

stattdessen geschrieben werden als:

try {
  const result = await doSomething()
  doSomethingWithResult(result)
} catch (e) {
  doSomethingWithError(e)
}
zzzzBov
quelle
3

Möglicherweise wird try / catch auch nicht sehr häufig in Javascript verwendet, da das Konstrukt in den allerersten Versionen von Javascript nicht verfügbar war ... es wurde später hinzugefügt.

Einige ältere Browser unterstützen dies daher nicht. (Tatsächlich kann es in einigen älteren Browsern zu einem Parser- / Syntaxfehler kommen, der schwieriger als die meisten anderen Fehlertypen zu "defensiven Programmen" führt.)

Da es ursprünglich nicht verfügbar war, wird es von den ursprünglich veröffentlichten integrierten Javascript-Funktionen (was man in vielen Sprachen als "Bibliotheks" -Funktionen bezeichnen würde) nicht verwendet. (Es funktioniert nicht sehr gut, einen Fehler von someobject.somefunction () zu "fangen", wenn er nicht "wirft", sondern nur "null" zurückgibt, wenn er auf ein Problem stößt.)


Ein weiterer möglicher Grund ist, dass der Try / Catch-Mechanismus anfangs nicht notwendig zu sein schien (und immer noch nicht so nützlich zu sein scheint). Dies ist nur dann wirklich erforderlich, wenn Anrufe routinemäßig mehrere Ebenen tief verschachtelt sind. Wenn Sie nur eine Art von ERRNO zurückgeben, funktioniert dies problemlos für Direktanrufe (obwohl es in den meisten Sprachen empfehlenswert ist, ERRNO überall und nicht nur für tief verschachtelte Anrufe zu verwenden, wenn es verfügbar ist ). Da ursprünglich angenommen wurde, dass die JavaScript-Logik klein und einfach ist (schließlich handelt es sich nur um eine Ergänzung zu einer Webseite :-), wurde nicht erwartet, dass Funktionsaufrufe tief verschachtelt sind, und daher schien ein Try / Catch-Mechanismus nicht erforderlich zu sein.

Chuck Kollars
quelle
3
Nein nein nein, absolut nicht der Fall. Motoren, die alt sind, spielen für eine LANGE Zeit keine Rolle mehr und die JavaScript-Community im Allgemeinen lässt alte Dinge schnell fallen, wenn dies gerechtfertigt ist. Ich würde sogar wetten, dass die Mehrheit der Javascript-Entwickler jetzt Post-IE6 ist.
Camilo Martin
0

Ich glaube, dass sie nicht so häufig verwendet werden, weil das Auslösen von Ausnahmen im clientseitigen Javascript-Code das Debuggen einer Seite erschwert.

Anstatt Ausnahmen auszulösen, ziehe ich es im Allgemeinen vor, ein Warnungsfeld (dh alert("Error, invalid...");) anzuzeigen.

Es mag seltsam klingen, aber auf Client-Seite treten Javascript-Fehler auf, wenn ein Kunde eine von Ihnen erstellte Seite verwendet und die Seite eine Ausnahme auslöst, es sei denn, der Kunde ist ein technisch versierter Programmierer , kann er dies niemals feststellen Sie, was das Problem ist.

Er wird Sie nur anrufen, indem er sagt: "Hey, Seite X funktioniert nicht!", Und dann müssen Sie herausfinden, was falsch gelaufen ist und wo im Code.

Wenn Sie stattdessen die Benachrichtigungsbox verwenden, ist es wahrscheinlicher, dass er anruft und etwas sagt wie: "Hey, wenn ich auf die Schaltfläche A von Seite X klicke, wird eine Box angezeigt, die sagt ..." , vertrauen Sie mir, es ist viel einfacher zu finden der Fehler.

Marco Demaio
quelle