ari*_*rio 2 javascript node.js express
我正在使用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
});
Run Code Online (Sandbox Code Playgroud)
即使用户名/传递组合不在数据库中,该页面也始终使用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
}
});
Run Code Online (Sandbox Code Playgroud)
包含A行的函数不会立即执行.相反,client.query立即返回并继续执行,直到B行.
然后当select查询返回时,执行回调函数.因此,按照执行的顺序,它可能会在 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);
});
Run Code Online (Sandbox Code Playgroud)
您可能会发现这会产生以下输出:
2
1
Run Code Online (Sandbox Code Playgroud)
因为第二个查询可能比第一个查询返回得更快.
这是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();
}
Run Code Online (Sandbox Code Playgroud)
这段代码不会马上工作,但请注意我是如何将res.render调用移动到一个函数中的,我正在调用client.query的回调函数.现在,您需要允许该回调访问res变量,方法是将其设置为全局(如果您在专用的"登录"模块中,这是好的,但在其他方面是个坏主意),或者将其传递给作为一个参数,这可能是更好的.
仅仅因为一行代码出现在另一行之后,并不一定意味着它会在它之后执行,如果涉及回调的话.你可能熟悉的类似行为的东西是超时; 考虑一下:
setTimeout(function() {
console.log(1);
}, 1000);
console.log(2);
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您应该会看到以下内容:
2
1
Run Code Online (Sandbox Code Playgroud)
与mysql查询之类的回调完全相同.而不是整个进程等待client.query返回,执行继续,您将依赖于client.query结果的所有内容放入您发送给client.query的回调中.