NodeJS 的一个优点是它的异步和非阻塞 I/O,在我的情况下,它一方面很棒,但另一方面每天都在折断我的脖子。
我认为自己是 NodeJS / Async 新手,我经常会得到这样的代码:
function(req, res) {
req.assert("name", "Lobbyname is required").notEmpty();
req.assert("name", "Lobbyname length should be between 4 and 64 characters").len(4, 64);
req.assert("game", "Game not found").isInt();
req.sanitize("game").toInt();
var userId = req.user.id;
var errors = req.validationErrors();
var pg_errors = [];
var games = null;
if (errors) {
console.log(errors);
client.query("SELECT * FROM games", function(err, result) {
if (!err) {
games = result.rows;
res.render("lobby/create", {
title: "Create a new lobby",
games: games,
errors: errors.toString()
});
}
else {
res.send("error");
}
});
}
else {
errors = null;
client.query("SELECT COUNT(*) as in_lobbies FROM users u RIGHT JOIN lobby_userlist ul ON ul.user_id = u.id WHERE u.id = $1", [userId], function(err, result) {
if (!err) {
console.log(result.rows[0]);
if (result.rows[0].in_lobbies < 1) {
client.query("SELECT COUNT(*) as hosting_lobbies FROM lobbies WHERE owner = $1", [userId], function(err, result) {
if (!err) {
if (result.rows[0].hosting_lobbies < 1) {
client.query("INSERT INTO lobbies(name, game, owner) VALUES($1, $2, $3)", [req.param("name"), req.param("game"), userId], function(err, result) {
if (!err) {
res.redirect("/lobby");
}
else {
pg_errors.push(err);
console.log(err);
}
});
}
else {
errors = "You can only host one lobby at a time";
}
}
else {
pg_errors.push(err);
client.query("SELECT * FROM games", function(err, result) {
if (!err) {
games = result.rows;
res.render("lobby/create", {
title: "Create a new lobby",
games: games,
errors: errors
});
}
else {
pg_errors.push(err);
}
});
}
});
}
else {
pg_errors.push(err);
}
}
});
console.log("pg_errors");
console.log(pg_errors);
console.log("pg_errors _end");
if (pg_errors.length < 1) {
console.log("no errors");
}
else {
console.log(pg_errors);
res.send("error service operation failed");
}
}
}
这是我使用以下 npm 包编写的示例:
- pg(本机)
- 表示
- express-validator(节点验证器的中间件)
- 护照(身份验证中间件)
检查用户给出的输入是否有效是最小的问题,我会检查我在哪里断言变量并将页面的渲染版本返回给用户打印出错误。
但是,如果我们首先通过验证错误,我们假设“大厅”已准备好插入数据库,然后我想确保用户没有其他大厅打开并且不是另一个大厅的成员。好吧,现在我最终将一个查询放入另一个查询中,理论上我必须将我的视图渲染函数(res.render())放入每个查询回调中,如果查询遇到错误或返回指示用户不被允许的结果创建一个大厅。我不想那样做,而且似乎不太实用。
我尝试从查询回调中删除渲染逻辑和所有其他逻辑,而是让查询回调设置指示成功或失败的错误数组或变量,并在我的查询代码下方检查 if(errors) renderPageWithErrors。
由于 nodejs 的异步行为,这会导致奇怪的错误,在这种情况下 res.redirect() 是在 res.render() 之后调用的,诸如此类。我不得不将我的 res.render 移回查询回调中。
有没有正确的方法来做到这一点?