I\'m new to Node.Js and JavaScript web development on the backend. I see that callbacks inside callbacks could be a pain and there are modules to avoid that. One of these mo
In my view, callback hell is really a mixture of two problems:
Either one in small amounts is fine, but together they make code rigid and unmaintainable. The solution to avoiding callback hell is to avoid these two things by:
Going by these principles, your code can be rewritten as:
function check_auth_user(username, password, done) {
// Make a new client and open the connection.
function connect(callback) {
var client = new pg.Client("pg://user:pass@127.0.0.1/database");
client.connect(function (err) {
if (err) {
console.error('could not connect to postgres', err);
return callback(err);
}
callback(null, client);
});
}
// Query the database.
function query(callback, results) {
var client = results.client;
var q = 'select * from "user" where username = $1 and password = $2';
var params = [username, password];
client.query(q, params, function (err, result) {
if (err) {
console.error('error running query', err.stack || err.message);
return callback(err);
}
callback(null, result);
});
}
// Do stuff with the result of the query.
function handleQueryResult(callback, results) {
var result = results.query;
if (result.rowCount === 0) {
return callback();
}
var row = result.rows[0];
console.log(row);
passport.serializeUser(function(res, done) {
done(null, res);
});
passport.deserializeUser(function(user, done) {
done(null, res);
});
callback(null, row);
}
// Let async handle the order. Allows remixing.
async.auto({
connect: [connect],
query: ['connect', query],
row: ['query', handleQueryResult]
}, function (err, results) {
if (err) {
return done(err);
}
// Callback with the row.
done(null, results.row);
});
}
I've used async.auto here, even if async.waterfall
would do. The reasoning behind that is that it's difficult to move, add or remove steps in a waterfall
, and that's been a source of bugs. The auto
lets you add steps without worrying and the order/parallelism is handled by async.
This is obviously using a lot more vertical space, but I think that's a small price to pay for the modularity.