为什么我的JS承诺会将错误对象捕获为空?

cca*_*ale 21 javascript error-handling try-catch node.js promise

前言:

  • 使用Mongoose
  • 使用Bluebird并替换Mongoose内部的mpromise
  • req.helpers.consoleMessage下面看到的函数是一个函数,其中包含一些简单的逻辑,根据应用程序配置中打开的调试的存在以及对象的非null /未定义状态确定何时显示和不显示某个级别的详细信息显示.整个消息使用字符串进行字符串化JSON并返回以显示在控制台上.

码:

以下是显示这些症状的一些代码示例.

这是我正在使用的API中delete:team :comment单元的路由.我故意var response = user.comments;在引用一个user对象时给它留下了一个错误,实际上它应该team由调用函数返回并传递给Promise .then().这应该导致引用错误,因为未定义用户.

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

    }
Run Code Online (Sandbox Code Playgroud)

症状:

调用此路由将产生错误并导致.catch()尝试从错误状态恢复,但该err对象似乎为空.

防爆.HTTP响应:{ success: false, message: {} }

防爆.控制台日志(为清晰起见删节){ req: {...}, res: {...}. err: {} }

结论:

err物体似乎是空的......

cca*_*ale 24

问题:

将错误对象单独记录到控制台将显示该对象确实不是空的并且抓取诸如err.message非常可行的属性.

问题是JS Error对象不能被天真地字符串化使用JSON.这个 - 以及处理这个问题的方法 - 在相关的SOF问题中有详细描述:是否不可能使用JSON.stringify对错误进行字符串化?.

更新的代码:

进行了以下代码更改以指定消息在HTTP响应中显示,并且辅助函数(先前描述)已更新为特定要显示的错误的详细信息:Ex:{ err: { message: err.message, stack: err.stack } }依此类推.

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

    }
Run Code Online (Sandbox Code Playgroud)

为什么我要分享这么简单的概念?

我搜索了几个小时,试图弄清楚我对我的承诺链结构做错了什么,并使用了关键字emptyerror(以及关于JS Promises的每个词组合)但我的搜索没有提出任何有用的东西,除了确认我是正确地接近这个.我的助手脚本似乎一切都很好,我似乎无法做正确的调试步骤来找出问题所在,直到我试图将err对象直接输出到控制台时(为什么我需要这样做?我已经......或者我认为).

所以我想你可以说我试图挽救一些人,以防万一有人遇到类似的情况并且正在思考"为什么我的承诺不按预期工作!" 就像我一样,碰巧正朝着错误的方向寻找.

快乐的编码!

  • 哈,我犯了同样的错误.对于我来说,这是今天堆栈溢出最有用的东西.谢谢. (4认同)

Dmi*_*nko 13

当您尝试使用空对象时会出现问题JSON.stringify

const error = new Error('Oops');
const output = JSON.stringify(error);
console.log(output); // {}
Run Code Online (Sandbox Code Playgroud)
const error = new Error('Oops');
const output = JSON.stringify(error.message); // <--- Use error.message to fix that
console.log(output); // "Oops"
Run Code Online (Sandbox Code Playgroud)


Mel*_*uso 5

对于那些想知道为什么它throw error()只是一个空对象的人来说,这是因为您需要将其记录为error.message访问它的message属性。