我正在使用 express 框架在 node.js 中为网站编写登录。但是,代码以奇怪的顺序执行,我不确定如何修复它。这是相关代码的简化版本:
app.post('/login', function(req, res){
var login_error;
if (!req.session.username) { //if no one is logged in
if (req.body.user != undefined && req.body.pass != undefined) {
client.query('USE data', function(error, results) {}
});
client.query('SELECT id FROM user WHERE username=? AND password=?',[reg.body.user, req.body.pass],
function(err, results,fields) {
if (err || results.length == 0) {
login_error=1;
console.log('a '+login_error); //LINE A
}
});
}
console.log('b '+login_error); //LINE B
if (login_error == undefined) {
req.session.username=req.body.user;
}
client.end();
}
res.render('login', {
user: req.session.username,
login_error: login_error
});
即使用户名/密码组合不在数据库中,页面始终呈现 login_error=undefined。在这种情况下,LINE A 正在打印 login_error=1,而 LINE B 正在打印 login_error=undefined。此外,LINE B 在 LINE A 之前打印,即使它出现得更晚。我不太确定这里发生了什么。
最佳答案
这是因为回调的工作方式。在这段代码中:
client.query('SELECT id FROM user WHERE username=? AND password=?',[reg.body.user, req.body.pass],
function(err, results,fields) {
if (err || results.length == 0) {
login_error=1;
console.log('a '+login_error); //LINE A
}
});
包含 A 行的函数不会立即执行。相反,client.query 会立即返回并继续执行,直到 B 行。
Then when the select query returns, your callback function executes.因此,按照执行顺序,它可能会在 B 行之后,即使它事先出现在源代码中也是如此。
考虑这个例子
client.query('SELECT 1 AS Res', function(err, results) {
console.log(results.fields.Res);
});
client.query('SELECT 2 AS Res', function(err, results) {
console.log(results.fields.Res);
});
您可能会发现这会产生以下输出:
2
1
因为第二个查询可能比第一个查询返回得更快。
这就是 Node 强大的源泉 - 代码不会阻塞,它是异步的,所以它很快。
为了让您的示例按预期运行,您应该重构它以在单独的函数中调用需要了解查询结果的代码。例如更像这样的东西:
function processLogin(login_error) {
console.log('b '+login_error); //LINE B
if (login_error !== true) {
req.session.username=req.body.user;
}
res.render('login', {
user: req.session.username,
login_error: login_error
});
}
app.post('/login', function(req, res){
if (!req.session.username) { //if no one is logged in
if (req.body.user != undefined && req.body.pass != undefined) {
client.query('USE data', function(error, results) {}
});
client.query('SELECT id FROM user WHERE username=? AND password=?',[reg.body.user, req.body.pass], function(err, results,fields) {
if (err || results.length == 0) {
process_login(true);
} else {
process_login(false);
}
});
}
client.end();
}
此代码不会立即运行,但请注意我是如何将 res.render 调用移动到一个函数中的,该函数是我从 client.query 的回调中调用的。现在,您需要允许该回调访问 res 变量,方法是将其设为全局变量(如果您在专用的“登录”模块中,这很好,但否则是个坏主意),或者将其传递给用作参数,这可能更可取。
仅仅因为一行代码接连出现,并不一定意味着它会在它之后执行,如果涉及到回调的话。您可能熟悉的类似行为是超时;考虑一下:
setTimeout(function() {
console.log(1);
}, 1000);
console.log(2);
在这种情况下,很明显您会看到以下内容:
2
1
这与对 mysql 查询之类的回调完全相同。不是等待 client.query 返回的整个过程,而是继续执行,您将依赖于 client.query 结果的所有内容放入您发送给 client.query 的回调中。
关于javascript - 使用 express 在 node.js 中编写登录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9057075/