web-dev-qa-db-de.com

Wie debuggen Sie Javascript-Versprechen?

Ich versuche zu verstehen, wie man asynchronen Code debuggt, der auf Versprechungen basiert. Mit Versprechungen meine ich ECMAScript 6-basierte Versprechen und mit Debuggen meine ich die Verwendung des eingebauten Chrome- oder Firefox-Debuggers.

Ich habe Probleme mit dem Problem: Wenn ein Fehler auftritt, scheint es mir nicht möglich zu sein, die Stack-Ablaufverfolgung zu ermitteln, egal wie ich es "ablehne".

Ich habe diese probiert:

console.log(new Error('Error occured'));
throw new Error('Throwing an Error');
return new Error('Error returned by the onRejected function');
reject(new Error('Pass Error to the reject function'));

Keine davon gibt jedoch den tatsächlichen Fehler im Code oder die Stack-Ablaufverfolgung zurück.

Meine Frage ist also - wie kann ich Javascript Promises richtig debuggen?

63
YemSalat

Dies ist ein großartiges Thema, das besprochen werden muss. Die traurige Nachricht ist, dass dies mit den Versprechungen der Einheimischen ziemlich hart ist.

Das Debuggen von rohen ES6-Versprechen in Chrome ist schrecklich. Dies liegt daran, dass sie Fehler im Stillen unterdrücken, und wenn Sie einen Fang weglassen, erhalten Sie keine Hinweise darauf, dass das Versprechen fehlgeschlagen ist. Update: Chrome protokolliert jetzt nicht behandelte Ablehnungen (Siehe diesen Link für wie)

 Promise.resolve("foo").then(function(){
      throw new Error("You will never see this");// silent failure
 });

In Firefox sind die Dinge ein bisschen besser, da sie eine unhandliche Ablehnungserkennung durchführen. Allerdings ist das immer noch unberechenbar und wenn Sie das Versprechen irgendwo vergeben, funktioniert es nicht.

Was kann man also tun?

Include Bluebird - Es ist eine Obermenge von ES6-Versprechen und Sie können es direkt austauschen, es verfügt über eine reichhaltigere API, ist schneller und hat erstaunliche Stack-Spuren. Es wurde im Hinblick auf das Debugging erstellt und enthält umfangreiche Fehlerbehandlungsfunktionen.

Wenn Sie Bluebird hinzugefügt haben, rufen Sie an:

Promise.longStackTraces();

Dadurch wird es etwas langsamer (es wird immer noch sehr schnell sein) und es werden Ihnen erstaunliche Fehlermeldungen angezeigt. Zum Beispiel:

Promise.resolve().then(function outer() {
    return Promise.resolve().then(function inner() {
        return Promise.resolve().then(function evenMoreInner() {
            a.b.c.d()
        });
    });
});

In nativen Versprechungen - dies wird ein stiller Fehler sein und wird sehr schwer zu debuggen sein - mit Bluebird-Versprechen wird dies einen großen roten Fehler in Ihrer Konsole zeigen, der standardmäßig Folgendes ergibt:

ReferenceError: a is not defined
    at evenMoreInner (<anonymous>:6:13)
From previous event:
    at inner (<anonymous>:5:24)
From previous event:
    at outer (<anonymous>:4:20)
From previous event:
    at <anonymous>:3:9
    at Object.InjectedScript._evaluateOn (<anonymous>:581:39)
    at Object.InjectedScript._evaluateAndWrap (<anonymous>:540:52)
    at Object.InjectedScript.evaluate (<anonymous>:459:21)

Wenn Sie mit dem Debuggen fertig sind, können Sie es austauschen und zu den ursprünglichen Versprechen zurückkehren. Persönlich schätze ich es zu wissen, dass ich Fehler in der Produktion habe, daher empfehle ich es nicht, aber es ist durchaus machbar.

57

* Dies beantwortet Ihre Frage nicht direkt, kann aber dennoch hilfreich sein.

Chrome devtools hat vor kurzem eine neue Funktion erhalten, die zum Debuggen von asynchronem Code wie Promises nützlich ist.

http://www.html5rocks.com/de/tutorials/developertools/async-call-stack/

Aktivieren Sie im Grunde das Kontrollkästchen "asynchron" auf der Registerkarte "Quellen", und Chrome rekonstruiert den Aufrufstapel so, als wäre es synchroner Code.

 Screenshot

13
goat

Diese Antwort ist eine Ergänzung zu Benjamin Gruenbaums Antwort: Wenn Sie in der Versprechungskette eine catch -Anweisung verwenden, erhalten Sie den Stack-Trace mit error.stack :

        Promise.longStackTraces();

        function outer() {
            return Promise.resolve();
        }

        function inner() {
            return Promise.resolve();
        }

        function evenMoreInner() {
            a.b.c.d()
        }

        Promise.resolve()
            .then(outer)
            .then(inner)
            .then(evenMoreInner())
            .catch(function (err) {
                    console.log(err.message);
                    console.log(err.stack);
                });

Fehlermeldung:

ReferenceError: a is not defined
at evenMoreInner (test/test_promise.js:58:17)  <<<< HERE's the error!
at Context.<anonymous> (test/test_promise.js:64:23)
12
Matthias M

Sie scheinen mit Debug-Tools in Chrome zu arbeiten. In diesem Thread finden Sie weitere Informationen.

https://code.google.com/p/v8/issues/detail?id=3093

Ich habe nicht überprüft, ob dies bereits in der Dev-Version oder der Beta-Version enthalten ist, aber ich hoffe, dass dies bald der Fall sein wird. Es könnte dann in der normalen Version im Januar 2015 enthalten sein oder so (nur eine persönliche Vermutung, absolut kein Versprechen, da ich nicht einmal für Google arbeite).

1
Johan Bergens

Sie können eine console.log () - Anweisung in die .then () - Funktion des Promise-Objekts einfügen: Sie können bei Bedarf auch die .catch () hinzufügen.

genericDbCaller(dbName, collectionName, dbFunctionName, params) {
        return new Promise((resolve, reject) => {
            DatabaseContext.instance.getDbConn(dbName)
                .then((dbConn) => {
                    dbConn.get(collectionName)[dbFunctionName].apply(null, params)
                        .then(

                            (docs) =>{
                    ----->>>        console.log(docs);  
                            resolve(docs);
                        })
                        .catch((e)=>{
0
cepix

Die versprochene Debugging-Methode besteht am besten darin, das unhandledRejection-Ereignis Ihrer process anzuhören.

So können Sie beispielsweise eine Stapelablaufverfolgung einrichten und ausgeben ...

 process.on('unhandledRejection', (reason, p) => {
   console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
   // Stack Trace
   console.log(reason.stack);
 });
0
ra9r