web-dev-qa-db-fra.com

Pourquoi ma promesse JS capture-t-elle les objets d'erreur vides?

Préface:

  • Utiliser Mongoose
  • Utilisation de Bluebird et remplacement de mpromise à l'intérieur de Mongoose
  • La fonction req.helpers.consoleMessage Vue ci-dessous est une fonction avec une logique simple qui détermine quand afficher ou non un certain niveau de détail en fonction de l'existant de débogage activé dans la configuration de l'application ET du non-null/état indéfini des objets affichés. L'ensemble des messages est stratifié à l'aide de JSON et renvoyé pour être affiché sur la console.

Code:

Voici un exemple de code montrant ces symptômes.

Il s'agit d'une route delete pour les unités :team:comment Dans une API sur laquelle je travaille. J'ai intentionnellement laissé la ligne var response = user.comments; Avec une erreur faisant référence à un objet user alors qu'en fait il devrait être team qui devrait être retourné par la fonction appelante et passé dans la fonction Promise.then(). Cela devrait provoquer une erreur de référence car l'utilisateur n'est pas défini.

    var console = clim("(DELETE /api/v1/team/:team/comments/:comment):", logger);

    // create a filters request for mongoose
    var query = {};

    // determine if the :team param is a username or an object id
    req.helpers.validateObjectId(req.db, req.params.team) ? query._id = req.params.team : query.name = req.params.team;

    if(req.helpers.validateObjectId(req.db, req.params.comment)) {

        // looks good; create an update object
        var update = { $pull: { comments: { _id: req.params.comment } } };

        // find the comment using the query above and pull the comment id
        req.models.Team.findOneAndUpdate(
            query,
            update,
            {safe: true, new : true}
        ).then(function(team){

            if(!team){

                // create the response object
                var response = {
                    success: false,
                    message: "Team not found"
                };

                // log request
                console.info(req.helpers.consoleMessage(req, response, null));

                // respond with an appropriate array
                res.status(404).json(response);

            }else{

                // create the response object using the teams's comments
                var response = user.comments;

                // log request
                console.info(req.helpers.consoleMessage(req, response, null));

                // respond with the team comments array
                res.status(200).json(response);

            }

        }).then(null, function(err){

            // create the response
            var response = { success: false, message: req.config.debug ? err: "An error has occur with your request; please try again" };

            // log the errors
            console.error(req.helpers.consoleMessage(req, response, err));

            // or send a 500 internal server error
            res.status(500).json(response);

        });

    }else{

        // create the response
        var response = { success: false, message: "Comment id is not a valid object id" };

        // log the errors
        console.info(req.helpers.consoleMessage(req, response, null));

        // or send a 500 internal server error
        res.status(500).json(response);

    }

Symptôme:

L'appel de cette route produira une erreur et provoquera la .catch() à déclencher dans une tentative de récupération de l'état erroné, cependant l'objet err semble être vide.

Ex. Réponse HTTP: { success: false, message: {} }

Ex. Journal de la console (abrégé pour plus de clarté) { req: {...}, res: {...}. err: {} }

Conclusion:

L'objet err semble vide ...

21
ccampanale

Problème:

La journalisation de l'objet d'erreur sur la console par elle-même révélera que l'objet n'est en effet pas vide et que les propriétés de capture telles que err.message est très faisable.

Le problème est que l'objet d'erreur JS ne peut pas être naïvement stratifié à l'aide de JSON. Ceci - ainsi que les moyens de résoudre ce problème - sont décrits en détail dans la question SOF associée: N'est-il pas possible de filtrer une erreur en utilisant JSON.stringify? .

Code mis à jour:

Les modifications de code suivantes ont été apportées pour spécifier le message à afficher dans la réponse HTTP et la fonction d'assistance (décrite précédemment) a été mise à jour pour spécifier les détails de l'erreur à afficher: Ex: { err: { message: err.message, stack: err.stack } } etc.

    var console = clim("(DELETE /api/v1/team/:team/comments/:comment):", logger);

    // create a filters request for mongoose
    var query = {};

    // determine if the :team param is a username or an object id
    req.helpers.validateObjectId(req.db, req.params.team) ? query._id = req.params.team : query.name = req.params.team;

    if(req.helpers.validateObjectId(req.db, req.params.comment)) {

        // looks good; create an update object
        var update = { $pull: { comments: { _id: req.params.comment } } };

        // find the comment using the query above and pull the comment id
        req.models.Team.findOneAndUpdate(
            query,
            update,
            {safe: true, new : true}
        ).then(function(team){

            if(!team){

                // create the response object
                var response = {
                    success: false,
                    message: "Team not found"
                };

                // log request
                console.info(req.helpers.consoleMessage(req, response, null));

                // respond with an appropriate array
                res.status(404).json(response);

            }else{

                // create the response object using the teams's comments
                var response = team.comments;

                // log request
                console.info(req.helpers.consoleMessage(req, response, null));

                // respond with the team comments array
                res.status(200).json(response);

            }

        }).then(null, function(err){

            // create the response
            var response = { success: false, message: req.config.debug ? err.message : "An error has occur with your request; please try again" };

            // log the errors
            console.error(req.helpers.consoleMessage(req, response, err));

            // or send a 500 internal server error
            res.status(500).json(response);

        });

    }else{

        // create the response
        var response = { success: false, message: "Comment id is not a valid object id" };

        // log the errors
        console.info(req.helpers.consoleMessage(req, response, null));

        // or send a 500 internal server error
        res.status(500).json(response);

    }

Pourquoi est-ce que je partage un concept aussi simple?

J'ai cherché pendant des heures à essayer de comprendre ce que je faisais incorrectement avec mes structures de chaîne de promesses et j'ai utilisé les mots clés empty et error (ainsi que toutes les combinaisons de mots concernant JS Promises), mais aucun de mes les recherches ont trouvé quelque chose d'utile autre que de confirmer que j'approchais cela correctement. Tout semblait bien se passer avec mon script d'aide et je n'arrivais pas à faire les bonnes étapes de débogage pour comprendre où était le problème jusqu'à ce que j'arrive en essayant de sortir l'objet err directement dans la console (pourquoi Je dois faire ça? Je l'étais déjà ... ou du moins je le pensais).

Donc je suppose que vous pourriez dire que j'essaie de faire gagner du temps à certaines personnes au cas où quelqu'un se retrouverait dans une situation similaire et se demanderait "pourquoi mes promesses ne fonctionnent-elles pas comme prévu!" et, comme moi, cherche dans la mauvaise direction.

Codage heureux!

25
ccampanale