我有一个 Node.js/Express 应用程序,它在路由中查询 MySQL 数据库并将结果显示给用户。我的问题是如何在将用户重定向到他们请求的页面之前运行查询并阻止直到两个查询都完成?
在我的示例中,我有 2 个查询需要在呈现页面之前完成。如果我将查询 2 嵌套在查询 1 的“结果”回调中,我可以让查询同步运行。但是,当查询数量增加时,这将变得非常复杂。
如何在不将后续查询嵌套在先前查询的“结果”回调中的情况下同步运行多个(在本例中为 2)数据库查询?
我查看了 Node 模块中的“流控制/异步好东西”并尝试了 flow-js,但我无法让它与异步查询一起使用。
下面列出的是我尝试从“/home”路由执行的 2 个查询。 Node 专家能否解释一下这样做的“正确”方法。
app.get('/home', function (req,res) {
var user_array = [];
var title_array = [];
// first query
var sql = 'select user_name from users';
db.execute(sql)
.addListener('row', function(r) {
user_array.push( { user_name: r.user_name } );
})
.addListener('result', function(r) {
req.session.user_array = user_array;
});
// second query
var sql = 'select title from code_samples';
db.execute(sql)
.addListener('row', function(r) {
title_array.push( { title: r.title } );
})
.addListener('result', function(r) {
req.session.title_array = title_array;
});
// because the queries are async no data is returned to the user
res.render('home.ejs', {layout: false, locals: { user_name: user_array, title: title_array }});
});
最佳答案
Node 的目标不是关心事情发生的顺序。这会使一些场景复杂化。嵌套回调并不可耻。一旦你习惯了它的外观,你可能会发现你实际上更喜欢这种风格。我愿意;很清楚将触发什么订单回调。如果需要,您可以放弃匿名函数以减少冗长。
如果你愿意稍微重构你的代码,你可以使用“典型的”嵌套回调方法。如果你想避免回调,有许多异步框架会尝试帮助你做到这一点。您可能想要查看的一个是 async.js (https://github.com/fjakobs/async.js)。每个示例:
app.get('/home', function (req,res) {
var lock = 2;
var result = {};
result.user_array = [];
result.title_array = [];
var finishRequest = function(result) {
req.session.title_array = result.title_array;
req.session.user_array = result.user_array;
res.render('home.ejs', {layout: false, locals: { user_name: result.user_array, title: result.title_array }});
};
// first query
var q1 = function(fn) {
var sql = 'select user_name from users';
db.execute(sql)
.addListener('row', function(r) {
result.user_array.push( { user_name: r.user_name } );
})
.addListener('result', function(r) {
return fn && fn(null, result);
});
};
// second query
var q2 = function(fn) {
var sql = 'select title from code_samples';
db.execute(sql)
.addListener('row', function(r) {
result.title_array.push( { title: r.title } );
})
.addListener('result', function(r) {
return fn && fn(null, result);
});
}
//Standard nested callbacks
q1(function (err, result) {
if (err) { return; //do something}
q2(function (err, result) {
if (err) { return; //do something}
finishRequest(result);
});
});
//Using async.js
async.list([
q1,
q2,
]).call().end(function(err, result) {
finishRequest(result);
});
});
对于一次性的,我可能只会使用引用计数类型的方法。只需跟踪您要执行的查询数量,并在它们全部完成后呈现响应。
app.get('/home', function (req,res) {
var lock = 2;
var user_array = [];
var title_array = [];
var finishRequest = function() {
res.render('home.ejs', {layout: false, locals: { user_name: user_array, title: title_array }});
}
// first query
var sql = 'select user_name from users';
db.execute(sql)
.addListener('row', function(r) {
user_array.push( { user_name: r.user_name } );
})
.addListener('result', function(r) {
req.session.user_array = user_array;
lock -= 1;
if (lock === 0) {
finishRequest();
}
});
// second query
var sql = 'select title from code_samples';
db.execute(sql)
.addListener('row', function(r) {
title_array.push( { title: r.title } );
})
.addListener('result', function(r) {
req.session.title_array = title_array;
lock -= 1;
if (lock === 0) {
finishRequest();
}
});
});
更好的方法是在每个“结果”回调中简单地调用 finishRequest(),然后在呈现响应之前检查非空数组。这是否适用于您的情况取决于您的要求。
关于database - 使用 Node.js 进行同步数据库查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6597493/