我刚开始尝试使用node(使用Express构建一个带有MySql数据库的简单网站)。
我基本上运行了Express提供的应用程序结构(这对于这个问题无关紧要)。我有一个文件routes/index.js
,它会导出每当我的主页发出请求时被点击的index
函数。 index.js
的内容是:
var db = require('../db');
exports.index = function(req, res){
db.getConnection(function(err, connection) {
connection.query('SELECT * FROM test_table', function (err, rows) {
var templateVariables = {
title: 'Index Page',
response: rows[0].text
};
res.render('index', templateVariables);
});
connection.end();
});
};
这显然是一个非常初步和轻量级的示例,但是在索引页面的这个特定GET
请求中,已经存在一组3深度的回调函数。每个callbuck必须存在于“parent”的回调中,因为它取决于结果(在顺序执行的语言/环境中,这将是显而易见的和微不足道的)。
我的问题是,在构建更复杂且可能非常大的应用程序时,如何避免出现大量嵌套回调函数的问题?当你对逻辑有顺序依赖时,这当然就是这种情况。我知道Node的理念是异步,但是当等待来自数据库的数据并说我们正在运行5个单独的查询时,那么呢?我们只是将单个多语句查询编写为原子单元吗?虽然这个问题不是数据库所独有的。
答案 0 :(得分:2)
这里有关于这个问题的一般性讨论: http://callbackhell.com/
此外,许多人使用像Async这样的模块来管理流量控制问题。
答案 1 :(得分:2)
由于您使用Express提及,您可以使用next()
作为回调的替代方法。
app.get('/',function first(req,res,next){
res.write('Hello ');
res.locals.user = req.user;
next();
//Execute next handler in queue
});
app.get('/',function second(req,res,next){
res.write('World!');
//Use res.locals.user
res.end();
});
//response shows Hello World!
路由处理程序使用额外的参数next
并按给定的顺序执行,直到其中一个返回响应。 next
根本不接受任何参数,或者将错误作为参数。您可以在res.locals
答案 2 :(得分:1)
使用Promise
或Future
库,例如Q
(在npm上可用)。
引用Q的自述文件,承诺让你转过身来:
step1(function (value1) {
step2(value1, function(value2) {
step3(value2, function(value3) {
step4(value3, function(value4) {
// Do something with value4
});
});
});
});
进入这个:
Q.fcall(step1)
.then(step2)
.then(step3)
.then(step4)
.then(function (value4) {
// Do something with value4
}, function (error) {
// Handle any error from step1 through step4
})
.done();
我见过回调地狱的其他解决方案引入了一些看似倒退的权衡。异步操作不形成较大操作之间的自然逻辑边界,因此如果您考虑函数或以其他方式模块化这些边界,您将获得微步代码。
答案 3 :(得分:1)
我喜欢做的一种方式就是这样......
exports.index = function(req, res) {
var connection
db.getConnection(gotConnection)
function gotConnection(err, _c) {
connection = _c
connection.query('SELECT * FROM test_table', gotData)
}
function gotData(err, rows) {
connection.end();
var templateVariables = {
title: 'Index Page',
response: rows[0].text
}
res.render('index', templateVariables);
}
});
你也应该总是在你的代码中处理错误,我假设你把它们遗漏了,以便在这里更容易阅读代码。