A demonstration of asynchronous code that starts off broken (db.close is invoked before the db calls return) then is parallelized by only returning the results after all db calls have returned, then leverages async.js to abstract away some of the logic. The last example simplified it even further by avoiding the IIFE that was needed to bind i to a given loop iteration.
// 1. BROKEN ASYNC CODE
var getDocuments = function(done) {
var ids = [1,2,3,4,5];
var results = [];
db.open()
for(var i=0; i<ids.length; i++) {
db.findById(ids[i], function(err, doc) {
results.push(doc);
});
}
// results is empty, because the for loop finishes before the findById callbacks finish
db.close()
done(results);
};
// 2. FIXED ASYNC CODE
var getDocuments = function(done) {
var ids = [1,2,3,4,5];
var results = [];
db.open()
for(var i=0; i<ids.length; i++) {
db.findById(ids[i], function(err, doc) {
results.push(doc);
// check if this is the last doc
if(results.length === ids.length) {
db.close()
done(results);
}
});
}
};
// 3. WITH ASYNC (needing an IIFE)
var getDocuments = function(done) {
var ids = [1,2,3,4,5];
var tasks = [];
for(var i=0; i<ids.length; i++) {
// use IIFE to bind i to a separate scope for each iteration of the loop
(function(i) {
// push loop functionality onto tasks array
tasks.push(function(cb) {
db.findById(ids[i], function(err, doc) {
cb(doc);
});
});
})(i);
}
db.open()
async.series(tasks, function(err, results) {
done(results);
db.close();
})
};
// 4. WITH ASYNC (using map)
var getDocuments = function(done) {
var ids = [1,2,3,4,5];
var tasks = ids.map(function(i) {
return function(cb) {
db.findById(ids[i], function(err, doc) {
cb(doc);
});
};
});
db.open();
async.series(tasks, function(err, results) {
done(results);
db.close();
})
};