【问题标题】:Callback code not executed回调代码未执行
【发布时间】:2015-12-07 19:27:55
【问题描述】:

这是我的代码:

socket.on('add user', function (data) {
    d('"add user" event');
    d(data, true);

    debugger;

    UserEngine.login({
        username: data.username, 
        password: data.password
    }, function(err, user) {
        if (err) {
            d('Bad Login. Username: ' + data.username);
            return;
        }

        /*
        ** Code after this comment is never executed 
        */

        debugger;
        d('Login OK: ' + data.username);

        socket.username = data.username;

        usernames[data.username] = data.username;
        ++numUsers;
        addedUser = true;
        socket.emit('login', {
            numUsers: numUsers
        });

        socket.broadcast.emit('user joined', {
            username: socket.username,
            numUsers: numUsers 
        });

        return;
    });
});

如果 UserEngine.login(...) 出错,注释前的 If 语句正常工作,回调返回。但如果该方法正常工作,则不会执行 If 语句之后的代码。 为什么?

编辑:

下面是 UserEngine 模块的代码: http://pastebin.com/u2DQJrV3

【问题讨论】:

  • 什么是用户引擎?
  • 这是一个模块,用于所有用户帐户感兴趣的操作。我已经添加了代码链接。
  • 听起来像是“正常工作”,但实际上并没有正常工作。您是否确认甚至调用了回调?我的假设是它不是,这表明问题源于 UserEngine 模型。
  • 我在其他地方使用了模块和登录方法,它可以工作。所以这很奇怪。当我调试这段代码时,它被跳过了。
  • 如何改进问题以帮助您分析问题?

标签: node.js callback socket.io


【解决方案1】:

我的猜测是您的代码在您的 login() 方法的某处抛出了异常,并且由于大部分代码是在异步回调中执行的,您可能无法在控制台中获得任何异常信息。

这里有几个调试这个问题的建议:

  1. 您需要通过login() 方法遵循确切的流程。如果您在问题中所说的是真的,那么它有时不会调用回调,您需要找出原因。遵循流程的最简单方法是在login() 方法的每个分支中插入一个唯一标记的console.log() 语句,这样您就可以准确地看到控制流的方向以及执行的内容和不执行的内容。一旦你找到了,你就可以输出各种值来看看为什么会这样,或者设置一个适当的断点并跟踪它。

  2. login() 方法或它调用的东西中也可能引发某种异常。如果您进入异步回调,异常可能不会记录在控制台中,因此事情可能会静默失败,并且可能只是跳过回调而控制台中没有显示任何内容。如果您怀疑某个特定位置存在异常,您可以将自己的异常处理程序放在那里并记录异常是什么。请记住,每个异步范围都需要自己的异常处理程序——您不能只在顶层使用一个异常处理程序。这是异步编码的复杂性,也是使用 Promise 代替普通回调更有用的一个原因,因为 Promise 系统将为您捕获所有异步异常并将其转换为以异常为原因的被拒绝的 Promise(因此异步异常不会不要默默地失败)。

  3. 如果您的 login() 方法执行 user.save() 代码分支,则存在逻辑问题。我已经在下面记录了这个问题,虽然我认为这不是你的主要问题 - 但它需要解决。

  4. 我还建议您将日志记录放在调用 UserEngine.login() 的位置,以便记录所有可能的回调值。

建议的日志记录:

UserEngine.login({
    username: data.username, 
    password: data.password
}, function(err, user) {

    // =========== Add this ============
    console.log("UserEngine.login() callback");
    console.log(err, user);

    if (err) {
        d('Bad Login. Username: ' + data.username);
        return;
    }

这是您的login() 方法中user.save() 路径的问题:

在您的login() 代码中,作为self._verifyToken() 函数调用的一部分,您需要更改以下内容:

   login: function(args, callback) {
            /**
             * username [String]
             * password [String]
             */

            var self = this;

            if (!args.username || !args.password) {
                    return callback(Error.genObj(Error.code.MISSING_PARAMS));
            }

            User.findOne({
                    username: args.username
            }, function(err, user) {
                    console.log('[Debug] In User.findOne(...) Callback;');

                    if (err) {
                            return callback(Error.genObj(Error.code.INTERNAL));
                    }

                    if (!user) {
                            return callback(Error.genObj(Error.code.TOKEN_AUTH_FAILED));
                    }

                    if (self._generateHash({ password: args.password, salt: user.salt }) != user.password) {
                            return callback(Error.genObj(Error.code.TOKEN_AUTH_FAILED));
                    }

                    self._verifyToken({
                            token: user.token,
                            username: args.username,
                            key: Config.tokenKey
                    }, function(err) {
                            if (err) {
                                    var token = self._generateToken({ username: args.username, key: Config.key });
                                    user.token = token;

                                    user.save(function(err) {
                                            if (err) {
                                                    return callback(Error.genObj(Error.code.INTERNAL));
                                            }

                                            return callback(null, user);
                                    });
                            }

                            return callback(null, user);
                    });
            });
    },

到这里:

   login: function(args, callback) {
            /**
             * username [String]
             * password [String]
             */

            var self = this;

            if (!args.username || !args.password) {
                    return callback(Error.genObj(Error.code.MISSING_PARAMS));
            }

            User.findOne({
                    username: args.username
            }, function(err, user) {
                    console.log('[Debug] In User.findOne(...) Callback;');

                    if (err) {
                            return callback(Error.genObj(Error.code.INTERNAL));
                    }

                    if (!user) {
                            return callback(Error.genObj(Error.code.TOKEN_AUTH_FAILED));
                    }

                    if (self._generateHash({ password: args.password, salt: user.salt }) != user.password) {
                            return callback(Error.genObj(Error.code.TOKEN_AUTH_FAILED));
                    }

                    self._verifyToken({
                            token: user.token,
                            username: args.username,
                            key: Config.tokenKey
                    }, function(err) {
                            if (err) {
                                    var token = self._generateToken({ username: args.username, key: Config.key });
                                    user.token = token;

                                    user.save(function(err) {
                                            if (err) {
                                                    return callback(Error.genObj(Error.code.INTERNAL));
                                            }

                                            return callback(null, user);
                                    });
                            } else {
                                // ======== put this in an else clause  ==========
                                return callback(null, user);
                            }
                    });
            });
    },

问题是,如果你从verifyToken() 收到错误,那么它将启动user.save(),但由于这是异步的,它会在user.save() 操作完成之前继续并执行return callback(null, user) 然后它user.save() 完成后会再次调用回调。

【讨论】:

  • 我将尝试使用 Promise 重写我的代码,并通知您。
  • 感谢您的帮助和耐心等待。问题是 UserEngine.login() 方法中的 User.findOne() 生成的异常,因为数据库存在连接问题。现在我将尝试完全切换到承诺。非常感谢!
猜你喜欢
  • 1970-01-01
  • 2020-07-03
  • 1970-01-01
  • 2013-02-28
  • 1970-01-01
相关资源
最近更新 更多