web-dev-qa-db-fra.com

Comment déboguer des promesses javascript?

J'essaie de comprendre comment déboguer un code asynchrone basé sur des promesses. Par promesses, j'entends les promesses basées sur ECMAScript 6 et par débogage, j'utilise le débogueur intégré de chrome ou de firefox.

Ce qui me pose problème - c’est que lorsqu’une erreur se produit, il me semble impossible d’obtenir la trace de la pile, peu importe comment je la «rejette».

J'ai essayé ceux-ci:

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'));

Mais aucun de ceux-ci ne renvoie l'erreur réelle dans le code, ni la trace de la pile.

Ma question est donc la suivante: comment déboguer correctement les promesses javascript?

63
YemSalat

C’est un excellent sujet à débattre, la triste nouvelle est que c’est en fait assez difficile avec des promesses faites par des autochtones.

Le débogage des promesses brutes de l’ES6 dans Chrome est horrible. En effet, ils supprimeront les erreurs en silence et chaque fois que vous omettez une capture, cela ne vous indiquera pas que la promesse a échoué. Mise à jour: Chrome enregistre désormais les rejets non gérés (voir ce lien pour savoir comment)

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

Dans Firefox, les choses vont un peu mieux car elles effectuent une détection de rejet non gérée - elle reste toutefois floue et si vous attribuez la promesse n'importe où, cela ne fonctionnera pas.

Alors, que peut-on faire?

Include Bluebird - c'est un super ensemble de promesses ES6 et vous pouvez l'échanger à l'intérieur, il possède une API plus riche, il est plus rapide et il possède des traces de pile étonnantes. Il a été conçu pour le débogage et comprend de grandes installations de traitement des erreurs.

Une fois que vous avez inclus Bluebird, appelez le:

Promise.longStackTraces();

Ce qui le ralentira un peu (ce sera encore très rapide) et vous donnera des messages d'erreur incroyables. Par exemple:

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

Dans les promesses natives - ceci sera un échec silencieux et sera très difficile à déboguer - avec les promesses de Bluebird, cela montrera une grosse erreur rouge dans votre console par défaut vous donnant:

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)

Une fois le débogage terminé, vous pouvez l’échanger et revenir aux promesses autochtones. Personnellement, j’apprécie d’avoir des erreurs de production, je ne le recommande donc pas, mais c’est certainement faisable.

57
Benjamin Gruenbaum

* Cela ne répond pas directement à votre question, mais cela peut néanmoins être utile.

Chrome devtools a récemment une nouvelle fonctionnalité utile pour le débogage de code asynchrone, tel que Promises.

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

Activez la case à cocher "asynchrone" dans l'onglet "Sources". Chrome reconstruira la pile d'appels pour vous comme s'il s'agissait d'un code synchrone.

 Screenshot

13
goat

Cette réponse est un ajout à la réponse de Benjamin Gruenbaum: Si vous utilisez une instruction catch dans la chaîne de promesses, vous obtenez le suivi de pile par 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);
                });

Message d'erreur:

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

Ils semblent travailler avec des outils de débogage dans Chrome. Voir ce fil pour plus d'informations.

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

Je n'ai pas vérifié si cela est déjà dans la version dev ou la version bêta, mais j'espère que ça le sera bientôt. Il pourrait alors être inclus dans la version normale en janvier 2015 ou à peu près (juste une supposition personnelle, absolument aucune promesse puisque je ne travaille même pas pour Google).

1
Johan Bergens

Vous pouvez ajouter une instruction console.log () dans la fonction .then () de l'objet Promise: Vous pouvez également l'ajouter dans .catch () si nécessaire.

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

La meilleure façon de déboguer promise est d'écouter l'événement unhandledRejection de votre process.

Par exemple, voici comment vous pouvez le configurer et vider une trace de pile ...

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