2015-06-04 13 views
24

Können Fehler von einem nicht erwarteten Async-Aufruf abgefangen, an eine ursprüngliche Kapselung von try/catch gesendet oder eine nicht abgefangene Ausnahme ausgelöst werden?Kann ich einen Fehler von async ohne Verwendung von erwarten?

Hier ist ein Beispiel dafür, was ich meine:

async function fn1() { 
    console.log('executing fn1'); 
} 

async function fn2() { 
    console.log('executing fn2'); 
    throw new Error('from fn2'); 
} 

async function test() { 
    try { 
     await fn1(); 
     fn2(); 
    } 
    catch(e) { 
     console.log('caught error inside test:', e); 
    } 
} 

test(); 

In diesem Szenario wird die von fn2 geworfen Fehler leise geschluckt werden, und auf jeden Fall nicht von den ursprünglichen try/catch gefangen. Ich glaube, dies ist das erwartete Verhalten, da fn2 höchstwahrscheinlich in die Ereignisschleife verschoben wird, um irgendwann in der Zukunft fertig zu werden, und test ist es egal, wann es fertig ist (was beabsichtigt ist).

Gibt es eine Möglichkeit, sicherzustellen, dass Fehler nicht versehentlich von einer Struktur wie dieser verschluckt werden, anstatt try/catch intern fn2 zu setzen und so etwas wie einen Fehler zu tun? Ich würde mich sogar mit einem nicht erfaßten Fehler begnügen, ohne zu wissen, wie man ihn fängt, denke ich - ich erwarte nicht, dass geworfene Fehler ein typischer Programmfluß mit dem sind, was ich schreibe, aber das Schlucken macht das Debuggen relativ nervig.

Seitliche Notiz, ich benutze Babel, um den Code mit der Babel-Laufzeit-Transformation zu transpilieren und mit Knoten auszuführen.

+0

Ich bin mir nicht sicher, was Sie erreichen möchten, aber gibt es einen Grund, Versprechen nicht zu verwenden? – Tom

+1

Verwenden Sie eine Versprechens-Bibliothek, die die Behandlung von unbehandelten Zurückweisungen unterstützt. – Bergi

+0

Tom, nicht wirklich, nein. Ich war absichtlich mit async/warte auf Versprechungen zu sehen, was mit ES7-Syntax zu diesem Zeitpunkt getan werden könnte, und das war ein Problem, über das ich während des Spiels lief. Bergi, ich werde mich definitiv darauf zurückziehen, wenn es zu diesem Zeitpunkt keine anderen Möglichkeiten gibt (was vermutlich der Fall ist). – dvlsg

Antwort

25

mit unhandled Umgang abgelehnt nativen Versprechen (und Asynchron/erwarten verwendet native Versprechen) ist ein jetzt unterstützte Funktion in V8. Es wird im neuesten Chrome verwendet, um Debuginformationen auszugeben, wenn ein abgelehntes Versprechen nicht behandelt wird. versuchen Sie Folgendes an the Babel REPL:

async function executor() { 
    console.log("execute"); 
} 

async function doStuff() { 
    console.log("do stuff"); 
    throw new Error("omg"); 
} 

function handleException() { 
    console.error("Exception handled"); 
} 

(async function() { 
    try { 
     await executor(); 
     doStuff(); 
    } catch(e) { 
     handleException(); 
    } 
})() 

Sie sehen, dass, obwohl die Ausnahme von doStuff() verloren geht (weil wir nicht await verwenden, wenn wir es nennen), Chrome meldet, dass ein abgelehnter Versprechen an die Konsole nicht behandelte war :

Screenshot

Dies ist auch in Node.js verfügbar 4.0+, obwohl es hören erfordert a special unhandledRejection event:

process.on('unhandledRejection', function(reason, p) { 
    console.log("Unhandled Rejection at: Promise ", p, " reason: ", reason); 
    // application specific logging, throwing an error, or other logic here 
}); 
+0

Ah, perfekt. Vielen Dank für die Links zu den GitHub-Problemen, ich werde diese im Auge behalten, und ich werde mich vorerst darauf konzentrieren, io.js zu verwenden, um zu testen, woran ich gerade arbeite. – dvlsg

+1

Ah, eine letzte Einschränkung - ich musste 'Prozess hinzufügen.on ('unhandledRejection', err => {throw err;}); 'um dies wie erwartet in io.js vorerst zu erreichen, basierend auf ihren [Unit Tests] (https://github.com/nodejs/ io.js/blob/master/test/parallel/test-versprechen-unbehandelt-rejektionen.js # L86). Immer noch ein wenig hacky, aber ich bekomme einen Fehler mit einer (Art von) nützlichen Stack-Trace, auf diese Weise. – dvlsg

+0

Spielen damit scheint es, dass ein Fehler, der von einer Async-Funktion ausgelöst wird, die ohne "erwarten" aufgerufen wird, nicht abgefangen werden kann. Ist das der richtige Blickwinkel? – Jehan

-6

Wenn Sie mit promises vertraut sind, sie verwenden. Wenn nicht, können Sie dieses Beispiel versuchen, Ihnen mehr asynchron zu machen codieren :)

function fn1(callback) { 
    console.log('executing fn1'); 
    callback({status: true}); 
} 

function fn2(callback) { 
    console.log('executing fn2'); 
    callback({status: false}); 
} 

function test() { 
    fn1(function(result) { 
     console.log('fn1 executed with status ' + result.status); 
    }); 

    fn2(function(result) { 
     console.log('fn2 executed with status ' + result.status); 
     if (result.status == false) { 
      console.log('error in fn2'); 
     } 
    }); 
} 

test(); 
+1

Danke für die Antwort. Ich verwende ES7 async/abwarts absichtlich in diesem Szenario. Ich weiß, ich bin stur, und ich verwende Features, die noch nicht einmal vollständig akzeptiert sind, aber sie verbessern die Syntax und Lesbarkeit meines tatsächlichen Codes erheblich (es beinhaltet lange/unendliche While-Loops innerhalb von Async-Funktionen mit 'erwarten' in den Loops). – dvlsg