这是我的代码:
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
答案 0 :(得分:0)
我的猜测是你的代码在login()
方法的某个地方抛出异常,并且因为大部分代码是在异步回调中执行的,所以你可能无法在控制台中获得任何异常信息。
以下是调试此问题的几个建议:
您需要遵循login()
方法的确切流程。如果你在问题中所说的是真的,那么它有时不会调用回调,你需要找出原因。遵循流程的最简单方法是在console.log()
方法的每个分支中插入唯一标记的login()
语句,以便您可以确切地了解控制流的方向以及执行的内容和不执行的内容。一旦找到,就可以输出各种值,看看为什么会这样,或者设置一个合适的断点并跟踪它。
在login()
方法或其调用的内容中也可能会出现某种异常。一旦你进入异步回调,异常可能不会在控制台中被记录,因此事情可能会无声地失败,并且可以跳过回调,而不会在控制台中显示任何内容。如果您怀疑特定位置存在异常,可以将自己的异常处理程序放在那里并记录异常。请记住,每个异步作用域都需要自己的异常处理程序 - 您不能在顶层使用一个异常处理程序。这是异步编码的复杂性,并且使用promises而不是普通回调的一个原因是大大更有用,因为promise系统将捕获所有异步异常,并将其转换为被拒绝的promise,异常为原因(所以async例外don& #39; t默默地失败。)
login()
方法存在逻辑问题,如果它出现user.save()
代码分支。我已经在下面记录了这个问题,虽然我不认为这是你的主要问题 - 但这是需要解决的问题。
我还建议您将日志记录放在调用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;
}
以下是user.save()
方法中login()
路径的问题:
在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()
,但由于它是异步的,它会继续并执行return callback(null, user)
之前user.save()
操作已完成,然后在user.save()
完成后再次调用回调。