Reputation: 1084
Using node.js/express.js, here is an example of a typical problem that I face with asynchronous code (function rendering a page on a request with 2 db call):
exports.index = function(req, res){
res.render('index', {
data1: getData1(),
data2: getData2()
});
};
Here is what one function could look like:
function getData1() {
var assets = db.get("assets");
assets.find().on('success', function (docs) {
// What to do ?
});
}
I tried using async.js which is a very helpful module, but I'm still missing knowledge on how to do with a case like this.
And can someone suggest good resources for best practice regarding asynchronous javascript coding ?
Upvotes: 1
Views: 515
Reputation: 6039
I usually do one of the following:
1) Nest your calls:
exports.index = function(req, res){
//first call
assets.getRecord(function (err, docs) {
// 2nd call
assets.getSomeOtherRecord(function (err, otherDocs) {
res.render('index', {
data1:docs,
data2: otherDocs
});
);
});
};
If your code is simple, and you don't mind running these one after the other, then this suffices. If those don't apply, I use approach #2:
2) Use async.js or Q as the other answers here show.
Resources for learning about async:
- http://net.tutsplus.com/tutorials/javascript-ajax/managing-the-asynchronous-nature-of-node-js/
- http://www.sebastianseilund.com/nodejs-async-in-practice
Upvotes: 0
Reputation: 48476
Use an asynchronous workflow library, such as async.
function getData1(done) {
var assets = db.get('assets');
assets.find().on('success', done);
}
function getData2(done) {
var assets2 = db.get('assets2');
assets2.find().on('success', done);
}
exports.index = function(req, res, next){
async.parallel({
d1: getData1,
d2: getData2
}, render);
function render (err, data) {
if (err) {
return next(err);
}
res.render('index', {
data1: data.d1,
data2: data.d2
});
});
};
In this way, you can stick to the callback(err, result)
style perpetrated throughout Node packages, while keeping your code sane and pretty. async provides methods to simplify your workflows. In this case, I used the async.parallel
method which allows you to run any amount of callbacks concurrently, and then runs the function provided as a second argument when the other callbacks is done.
Upvotes: 1
Reputation: 126052
One way to solve your problem would be to chain the asynchronous commands by passing a callback function to the functions performing the asynchronous operations:
exports.index = function(req, res){
getData1(function (data1) {
getData2(function (data2) {
res.render('index', {
data1: data1,
data2: data2
});
});
});
};
function getData1(callback) {
var assets = db.get("assets");
assets.find().on('success', callback);
}
// Similarly for getData2
However, the nested callbacks can become unmanageable quickly. You can name the functions to help with this:
exports.index = function(req, res){
var data2Success = function (data1, data2) {
res.render('index', {
data1: data1,
data2: data2
});
},
data1Success = function (data1) {
getData2(data2Success.bind(this, data1));
};
getData1(data1Success);
};
Upvotes: 0