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 modules is async, https://github.com/caolan/async
I've read the documentation but it is hard to start and understand how to do it.
For example, I've this function "check_aut_user", How can I convert this code using async?
function check_auth_user(username, password, done) {
var client = new pg.Client("pg://user:pass@127.0.0.1/database");
client.connect(function(err) {
// If not get the connection
if(err) { return console.error('could not connect to postgres', err); }
// Query the user table
client.query('select * from "user" where username = $1 and password = $2', [username, password], function(err, result) {
if(err) { return console.error('error running query', err); }
if (result.rowCount > 0) {
var res = result.rows[0];
console.log(res);
passport.serializeUser(function(res, done) {
//console.log("serializer: " + res);
done(null, res);
});
passport.deserializeUser(function(user, done) {
//console.log("deserializer: " + user['password']);
done(null, res);
});
return done(null, res);
} else {
return done(null, false);
}
});
});
}
Best Regards,
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:
I've used
async.auto
here, even ifasync.waterfall
would do. The reasoning behind that is that it's difficult to move, add or remove steps in awaterfall
, and that's been a source of bugs. Theauto
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.
Here is the code modified to use async whenever needed.
Obviously, it does not make the code any more readable. I would suggest additional changes:
These two methods would both take callbacks. Here is a re-write:
Thus, our main method now becomes:
I hope you can see how this is much much better.
There are ways to combat runaway nesting using functional programming techniques. I use the
curry
module to break loop bodies out into stand-alone routines; usually this carries a very minor performance hit versus nesting (studycurry
for why). Example:Instead of:
The second example is more compact, but the more nesting you add, the less readable it becomes. Also, by splitting up the implementation, you can reuse component functions in multiple ways, and you can write unit tests for the individual component functions, not only for the high-level functionality.