2016-04-22 6 views
0

Warum verhalten sich native Promises wie ein Versuch/Haken bei Syntaxfehlern?Warum erfassen Promises Syntaxfehler?

Versprechen haben eindeutig einen Wert in der Flusskontrolle, wenn Sie eine Reihe von asynchronen Operationen in der richtigen Reihenfolge durchführen müssen. Aber die Notwendigkeit, Ihre eigenen unangemessenen Fehler bei der Implementierung von Implementierungen für jedes Versprechen zu implementieren, macht es manchmal schwierig, mit ihnen zu arbeiten.

Nehmen Sie den folgenden Code ein:

asdf 
 

 
let one = new Promise((resolve, reject) => { 
 
    asdf 
 
}).catch(err => { 
 
    console.log(err) 
 
    console.log(err.stack) 
 
})

Die erste Syntaxfehler erzeugt einen typischen Browser-Fehler und einen Stack-Trace mit 18 Einträgen. Die versprochene Version hat 4.

Also meine Frage ist, warum, wenn Sie die Spezifikation schreiben und nativ implementieren, behielten sie die Try/Catch-ähnliche Funktionalität der Userspace-Implementierung von Versprechen, so dass es für den Fluss verwendet werden konnte Kontrolle, aber lassen Sie die Standardfehlerbehandlung?

+3

Denn das ist kein Syntaxfehler, sondern ein Referenzfehler (möglicherweise) auftritt in der Zukunft. – Bergi

+1

Beachten Sie, dass die Fehler ReferenceErrors und nicht SyntaxErrors sind. Letzteres kann nicht abgefangen werden, da die Engine nicht gut genug versteht, um das Skript auszuführen. Aber 'asdf' ist ein gültiger Bezeichner und der Zugriff auf eine Variable allein ist eine gültige Anweisung. Also, der Parser findet keine Probleme damit. –

+0

Nicht sicher, ob dies ein geeignetes Duplikat ist: [Warum werden Ausnahmen für die Ablehnung von Versprechungen in JS verwendet?] (Http://stackoverflow.com/q/21616432/1048572) Bitte kommentieren Sie, wenn es sich bei Ihrer Frage um einen anderen Punkt handelt. – Bergi

Antwort

3

Ein tatsächlicher Syntaxfehler wird vom Javascript-Parser ausgelöst, wenn der Code geladen wird und immer noch eine geworfene Ausnahme sein wird. Grundsätzlich, wenn der Parser entscheidet, dass er den Code nicht richtig analysieren kann, gibt es an dieser Stelle nichts anderes zu tun. Es gibt auf und hört auf, den Rest des Codes zu analysieren.

Es ist Laufzeitfehler (die während der Codeausführung nicht während des Ladens/Parsens auftreten), die verspricht, zu behandeln.

Nach Spezifikation Versprechen Handler sind "sicher werfen", was bedeutet, dass sie geworfene Ausnahmen in abgelehnte Versprechen verwandeln. Dies geschieht, weil diese Handler immer asynchron sind und ausgelöste Exceptions in asynchronen Callbacks ziemlich nutzlos sind, da sie nicht vom aufrufenden Code abgefangen werden können, da der aufrufende Code nicht mehr auf dem Stack ist und der aufrufende Code nur über Callbacks mitgeteilt werden kann. Die Ausnahmen enden in einer asynchronen Infrastruktur, in der kein aufrufender Code sie abfangen oder behandeln kann. Daher haben sie eine Entscheidung getroffen, Ausnahmen in eine Zurückweisung umzuwandeln, so dass alle normalen Zurückweisungsbehandlungen und Fehlerausbreitungen, die versprechen, verwendet werden können.

Und weil Ausnahmen nicht durch den aufrufenden Code abgefangen werden können, wenn Versprechungen dies nicht taten, dann müssten Sie Ihren eigenen Versuch machen/fangen in praktisch alle Handler, um sicherzustellen, dass Sie etwas gefangen falsch machen. Es spart also viel zusätzlichen Code und macht es einfach sicherzustellen, dass alle asynchronen Ausnahmen korrekt abgefangen werden und der Fehler an den aufrufenden Code weitergegeben wird.

Kurz gesagt, wenn man sich einmal daran gewöhnt hat, ist es unglaublich nützlich und da eine Ausnahme, die nirgendwohin führt, nutzlos ist, würde ich sagen, dass die Designer eine sehr gute Wahl getroffen haben, indem sie sich entschieden haben, die Ausnahmen zu nutzen . Zu Ihrer Information, Sie können immer noch Ihre eigenen Versuch/fangen in einem Handler und tun, was Sie wollen, wenn Sie es wünschen.

0

Der Grund ist, denn wenn Sie mit einem asynchronen Prozess beschäftigen, haben Sie niemand, um Ihren Fehler zu fangen. Der vorherige Callstack ist weg.

Nämlich:

function simulateAsyncError() { 
    try { 
    setTimeout(function() { throw new Error("Nobody caught me"); }, 1); 
    console.log("I have set the future error."); 
    } catch (err) { console.log("I caught it!"); } 
} 

simulateAsyncError(); 
// "I have set the future error." 
// Uncaught Error: "Nobody caught me" 

Versprechungen sind über die Verpackung, und damit umzugehen.

+0

Ich bin völlig verwirrt durch den Downvote, wie das Beispiel die Frage am unteren Rand des ursprünglichen Beitrags perfekt beantwortet. – Norguard

1

Versprechungen erfassen nicht Ihre typischen Syntaxfehler, die bei der Syntaxanalyse/Kompilierung auftreten. Ihr Beispiel ist kein SyntaxError (der Parser versteht nicht, was Ihr Code ist), es ist ein ReferenceError (der Interpreter/runtime kann den von Ihnen angegebenen Bezeichner nicht finden).

Uncaught ReferenceError: asdf is not defined 

Wenn es einen Syntaxfehler im wörtlichen Code war, es wäre nicht haben gefangen. Das ist, was wir erwarten sollten: Wenn es den Code nicht analysieren kann, kann es nicht wissen, dass Sie sogar ein Versprechen erstellt haben.

let one = new Promise((resolve, reject) => { 
    foo bar baz 
}).catch(err => { 
    // ignore error 
}); 
Uncaught SyntaxError: Unexpected identifier 

Beachten Sie, dass, wenn Sie eval verwenden, um einen Syntaxfehler zur Laufzeit (aus Sicht des Verheißung betriebenen Code) zu erzeugen, wird er gefangen werden. Die Unterscheidung besteht nicht zwischen den JavaScript-Objekttypen der Fehler, die Unterscheidung ist zwischen Kompilierzeit und Laufzeitfehlern.

let one = new Promise((resolve, reject) => { 
    eval("foo bar baz"); 
}).catch(err => { 
    console.log("Captured error:", err); 
}) 
Captured error: SyntaxError: Unexpected identifier