The goal with node is not to care about the order in which events occur. This can complicate some scenarios. There is no shame with nested callbacks. Once you get used to how it looks, you may find that you really prefer this style. I do; itโs very clear which callbacks will fire. You can opt out of anonymous functions to make it less verbose if you need to.
If you want to slightly modify the structure of the code, you can use the "typical" nested callback method. If you want to avoid callbacks, there are many asynchronous frameworks that will try to help you with this. One that you can check out is async.js (https://github.com/fjakobs/async.js). An example of each of them:
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); }); });
For a one-time use, I would probably just use an approach like link counting. Just keep track of how many queries you want to complete, and draw an answer when they are all done.
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(); } }); });
An even nicer approach would be to simply call finishRequest () on each result callback to check for non-empty arrays before you post the answer. Whether this will work in your case depends on your requirements.