Ausnahmebehandlung geworfen, Fehler, innerhalb verspricht
Ich bin mit dem externen code als 3rd-party-Erweiterung zu einer node.js service. Die API-Methoden liefern verspricht. Gelöst Versprechen bedeutet, dass die Aktion erfolgreich durchgeführt wurde, einem gescheiterten Versprechen bedeutet, dass gab es einige problem mit der Durchführung der operation.
Nun, hier ist, wo ich Probleme habe.
Da der 3rd-party-code unbekannt ist, könnte es bugs, Fehler in der syntax, geben Sie Probleme, eine beliebige Anzahl von Dingen, die verursachen könnte node.js eine Ausnahme geworfen werden.
Jedoch, da der gesamte code, der eingewickelt ist in verspricht, diese geworfenen exceptions sind eigentlich wieder als gescheitert verspricht.
Habe ich den Funktionsaufruf in einen try/catch-block, aber es ist noch nie ausgelöst:
//worker process
var mod = require('./3rdparty/module.js');
try {
mod.run().then(function (data) {
sendToClient(true, data);
}, function (err) {
sendToClient(false, err);
});
} catch (e) {
//unrecoverable error inside of module
//... send signal to restart this worker process ...
});
In dem obigen Pseudo-code Beispiel, wenn ein Fehler geworfen wird, verwandelt es sich bis in die gescheiterten Versprechen der Funktion und nicht in den catch.
Aus, was ich lese, dies ist ein feature, nicht ein Problem, mit dem Versprechen. Aber ich habe Probleme beim wickeln meinem Kopf herum, warum würden Sie wollen immer zur Behandlung von Ausnahmen und erwarteten Ablehnungen genau das gleiche.
Einem Fall ist über den tatsächlichen Fehler im code, möglicherweise unwiederbringlich-das andere ist nur möglich, fehlende Konfiguration Informationen oder parameter, oder etwas wiederhergestellt werden.
Vielen Dank für jede Hilfe!!!
- Das design ist, dass es keine erwarteten Ablehnungen (ich mag es nicht), die eigentliche Funktion ist, dass Ausnahmen die gemeldet werden, auch wenn geworfen, das in der asynchronen code
- da der server neu ist viel mehr wünschenswert? wat
- Wie sonst unbekannten Ausnahmen soll behandelt werden? Ich würde es vorziehen, zu fangen, bekannte Ausnahmen von hand auslösen und die Ablehnung manuell, und verwenden Sie domains/Fenster.onerror - /Prozess.onuncaughtexceptions für alles andere.
- durch schließen Sie alle geöffneten Ressourcen und meldet einen Fehler an den Benutzer? Haben Sie immer noch zum Absturz des Servers, selbst wenn Sie nicht abgefangene Ausnahme, weil Sie nicht wissen, welche Ressourcen wurden offen gelassen.
- Das natürlich auch, aber es wird empfohlen, um noch den Prozess starten danach
- Ja, aber wenn du try-catch-finally-lokal (wie in Versprechen), die Sie nicht haben, um crash-beliebigen server, weil Sie die Handhabung der Fehler lokal genau dort, wo es passiert ist. spion.github.io/posts/why-i-am-switching-to-promises.html
- Sicher, ich versuche das auch, wo es möglich ist, und ich mag zu verwenden, verspricht für es (manuell). Doch aktuelle Versprechen design nicht zu "werfen weltweit", dieses "immer-local-try-catch" führt zu vergessen
done()
s etc... - Verspricht sollte das gleiche tun wie sync-code, sync code Fehler abzufangen, wenn Sie versuchen-fangen, so was würden Sie tun, mit sync-code?
- Ich mag es nicht, dass Vergleich. Vielleicht verspricht, kann mächtiger sein, als sync-code? 🙂
- das wäre nicht mehr mächtig, aber überraschende und zufällige Verhalten, wenn Sie versuchen zu fangen, dann haben Sie versuchen Sie zu fangen. Beachten Sie, dass zum Beispiel mein Versprechen Umsetzung können Sie ganz einfach hören bestimmte Art von Fehlern und die Programmierer Fehler hier ist leicht debugfähiger wenn man sich in der Konsole jsfiddle.net/sU9UN, Aber erwarten wie Diskriminierung auf Fehler-Arten erfolgt auf library-Ebene automatisch würde nicht gut gehen.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Absturz und Neustart eines Prozesses ist keine gültige Strategie zum Umgang mit Fehlern, nicht einmal bugs. Es wäre schön, Erlang, wo ein Prozess ist Billig und hat eine isolierte Sache, wie dienen einem einzigen client. Das gilt nicht in Knoten, wo ein Prozess kostet um Größenordnungen mehr und dient Tausende von Kunden auf einmal
Können sagen, dass Sie haben 200 Anfragen pro Sekunde, serviert von Ihrem service. Wenn 1% von denen trifft eine Wurf-Pfad im code, würden Sie bekommen 20 Prozess Abschaltungen pro Sekunde, etwa eines alle 50ms. Wenn du 4 Kerne mit 1 Prozess pro Kern, würden Sie Sie verlieren, in 200ms. Also, wenn ein Prozess dauert mehr als 200ms zu starten und vorbereiten, um Anfragen zu bedienen (minimale Kosten um 50ms für einen Knoten Prozess, der nicht jeder laden von Modulen), haben wir jetzt eine erfolgreiche insgesamt denial-of-service. Nicht zu erwähnen, dass Benutzer durch eine Fehlermeldung dazu neigen, Dinge zu tun wie z.B. immer wieder die Seite aktualisieren, damit verschärft das problem.
Domains lösen nicht das Problem, weil Sie kann nicht sicherstellen, dass die Ressourcen nicht durchgesickert.
Lesen Sie mehr auf Probleme #5114 und #5149.
Nun können Sie versuchen, "intelligent" über dies und haben eine Prozess-recycling-Politik von einer Art auf eine bestimmte Anzahl von Fehlern, aber was auch immer-Strategie, die Sie Ansatz wird es schwer ändern der Skalierbarkeit Profil von Knoten. Wir reden hier mehrere Dutzend Anfragen pro Sekunde verarbeiten, anstatt mehrere Tausende.
Jedoch verspricht alle Ausnahmen abfangen und dann propagieren Sie in einer Art und Weise sehr ähnlich wie synchrone exceptions propagieren den Stapel. Zusätzlich bieten Sie oft eine Methode
finally
was gemeint ist, ein äquivalent vontry...finally
Dank dieser beiden Funktionen können wir Kapseln, die clean-up-Logik durch den Bau der "context-Manager" (ähnlichwith
im python undusing
im C#), die immer um Ressourcen zu löschen.Können davon ausgehen, unsere Ressourcen als Objekte dargestellt werden, die mit
acquire
unddispose
Methoden, die beide die Rückkehr verspricht. Keine verbindungen hergestellt werden, wenn die Funktion aufgerufen wird, werden wir erst dann wieder ein resource-Objekt. Dieses Objekt wird vonusing
später:Wollen wir die API, wie folgt zu arbeiten:
Können wir leicht erreichen, die diese API:
Die Ressourcen werden immer entsorgt werden, nachdem die Versprechen Kette innerhalb zurückgegeben mit der
fn
argument abgeschlossen wird. Selbst wenn ein Fehler ausgegeben wurde innerhalb dieser Funktion (z.B. vonJSON.parse
) oder seine innere.then
Schließungen (wie in der zweitenJSON.parse
), oder wenn ein Versprechen in der Kette abgelehnt wurde (entspricht callbacks aufrufen mit einer Fehlermeldung). Dies ist der Grund, warum es so wichtig für die verspricht, die Fehler abfangen und verbreiten Sie.Wenn jedoch die Entsorgung der Ressource wirklich ausfällt, das ist in der Tat ein guter Grund zu kündigen. Seine sehr wahrscheinlich, dass wir haben zugespielt, eine Ressource, in diesem Fall, und es ist eine gute Idee zu starten, den Ausstieg aus diesem Prozess. Aber nun sind unsere Chancen für einen Absturz sind isoliert von einer sehr viel geringeren Teil unseres code - der Teil, der tatsächlich befasst sich mit leakable Ressourcen!
Hinweis: kündigen ist im Grunde wirft out-of-band, so dass verspricht kann es nicht fassen, z.B.
process.nextTick(() => { throw e });
. Was die Umsetzung Sinn macht, könnten abhängig von Ihrer Einrichtung - ein nextTick basiert, arbeitet ähnlich wie Rückrufe Abbrechen.Wie über die Verwendung von callback-basierten Bibliotheken? Sie könnte potenziell gefährlich sein. Betrachten wir ein Beispiel, um zu sehen, Woher diese Fehler kommen könnten, aus, und welche Probleme verursachen könnte:
mayThrowError2()
ist in einem inneren Rückruf und weiterhin den Prozess zum Absturz, wenn er wirft, auch wennunwrapped
aufgerufen wird ein anderes Versprechen ist.then
. Diese Art Fehler sind nicht gefangen von dem typischenpromisify
- Wrapper und wird auch weiterhin die Ursache eines Absturzes Prozess wie gewohnt.Jedoch
mayThrowError1()
gefangen werden, durch das Versprechen, wenn es innerhalb.then
, und die innere zugeordnete Ressource könnte Auslaufen.Können wir schreiben eine paranoide version von
promisify
das macht Sie sicher, dass alle geworfen, Fehler sind nicht behebbar und den Prozess zum Absturz:Mithilfe der promisified Funktion innerhalb einer anderen Versprechen die
.then
Rückruf führt jetzt mit einem Prozess zum Absturz bringen, wenn ausgepackt wirft, fällt zurück auf das zu werfen-crash-Paradigma.Seine die Allgemeine Hoffnung, dass, wie Sie mehr und mehr nutzen Versprechen basierten Bibliotheken, würden Sie den Kontext-manager Muster zu verwalten, Ihre Ressourcen und daher würden Sie weniger brauchen zu lassen, den Prozess zum Absturz.
Keiner dieser Lösungen sind kugelsicher - auch nicht der Absturz auf Fehler geworfen. Es ist sehr einfach, versehentlich schreiben Sie code, der verliert Ressourcen, obwohl Sie nicht werfen. Zum Beispiel, dieser Knoten-Stil-Funktion werden Ressourcen, obwohl Sie nicht throw:
Warum? Denn wenn
doSomething
's callback erhält eine Fehlermeldung, den code vergisst, über die Ressource verfügen.Diese Art von problem geschieht nicht mit context-Manager. Sie können nicht vergessen, zu rufen, zu entsorgen: Sie haben nicht zu, da
using
tut es für Sie!Referenzen: warum ich den Wechsel zu Versprechen, Kontext-Manager und Transaktionen
if (err) return callback(err);
ohne Absturz Prozess. Ist es leider ein "best-effort" - Lösung, nicht bullet-proof ein.Ist es fast das wichtigste feature verspricht. Wenn Sie nicht da war, Sie könnte genauso gut verwenden Rückrufe:
(Bevor Sie sagen, dass
JSON.parse
ist die einzige Sache, wirft in js, wussten Sie, dass auch die Nötigung einer variable eine Zahl z.B.+a
zu werfenTypeError
?Jedoch der obige code ausgedrückt werden kann, sehr viel deutlicher mit dem Versprechen, weil es gibt nur eine Ausnahme-Kanal statt 2:
Beachten Sie, dass
catch
Zucker für.then(null, fn)
. Wenn Sie verstehen, wie die Ausnahme-flow funktioniert Sie werden sehen, es ist ein bisschen von einer anti-pattern zu verwenden normalerweise die.dann(fnSuccess, fnFail)
.Der Punkt ist nicht an allen zu tun
.then(success, fail)
über, function(fail, success)
(I. E. es ist nicht eine alternative Möglichkeit zur Befestigung Ihres Rückrufe) sondern um eine schriftliche code Aussehen, fast so, wie es Aussehen würde, wenn das schreiben synchronous code:(Die sync-code wird tatsächlich immer hässlicher in der Realität, weil javascript nicht typisiert Fänge)
console.log(resalt)
(Tippfehler), was passieren würde, mit dem synchronen code?readFileSync
ohne try-catch.Versprechen Ablehnung ist einfach eine aus der Abstraktion Versagen. So sind Knoten-Stil Rückrufe (err, res) und Ausnahmen. Da verspricht asynchron sind kann man nicht mit try-catch fängt eigentlich nichts, denn ein Fehler dürfte nicht passieren in der gleichen tick von event-Schleife.
Ein kurzes Beispiel:
Hier können wir fangen einen Fehler, als Funktion ist synchron (obwohl callback-basiert). Weiteres:
Nun, wir können nicht fangen die Fehler! Die einzige Möglichkeit ist, pass es in der Rückruf:
Jetzt funktioniert ' s genau wie im ersten Beispiel.Das gleiche gilt für zusagen: Sie können nicht mit try-catch, so verwenden Sie Ablehnungen für error-handling.