Node.js Async only doing one callback - node.js

I'm just doing my first bit of Node async stuff, I wanted to do two queries to a DB and then print the results one after the other, my code is as follows:
console.log(req.query);
function logAllThings(err,things){
if (err){
console.log(err);
} else {
console.log(things);
};
};
async.parallel([
function(callback) { //This is the first task, and callback is its callback task
Event.find({}, function(err, events) {
logAllThings(err,events);
});
},
function(callback) { //This is the second task, and callback is its callback task
Organisation.find({}, function(err,organisations) {
logAllThings(err,organisations);
}); //Since we don't do anything interesting in db.save()'s callback, we might as well just pass in the task callback
}
], function(err) { //This is the final callback
console.log('Both should now be printed out');
});
The issue I have is that the second function (the one that returns organisations) prints them fine. However the one that is meant to return events simply does not and returns {} despite the fact I know the query works as I've tested it elsewhere.
Any help would be appreciated
Thanks

You have to call the callback function passed to each of your waterfall functions, otherwise it won't know when it's finished. Try this:
async.parallel([
function(callback) { //This is the first task, and callback is its callback task
Event.find({}, function(err, events) {
if (err) return callback(err);
logAllThings(err,events);
callback();
});
},
function(callback) { //This is the second task, and callback is its callback task
Organisation.find({}, function(err,organisations) {
if (err) return callback(err);
logAllThings(err,organisations);
callback();
}); //Since we don't do anything interesting in db.save()'s callback, we might as well just pass in the task callback
}
], function(err) { //This is the final callback
console.log('Both should now be printed out');
});

Related

Async.eachOfSeries not looping

I tried aysnc.eachOfSeries but the code does not loop. It stops executing in the first iteration itself and freezes. I guess I made some error in returning the callback.
I also tried putting a callback inside the else block but gives callback already called error.
This async.eachOfSeries is nested inside one more eachOfSeries.
async.eachOfSeries(data, function (value2, val, callback) {
let jsonObj = data[val];
let email = jsonObj.ToEmail;
jsonObj['retailer'] = res[camp].retailer;
jsonObj['summary'] = 'f';
let tempObj = {};
tempObj[id] = jsonObj;
let options = { new: true};
let campId = id;
User.addCampaignResponse(email, campId, tempObj, options, function (err, results) {
if (err) {
throw err;
} else {
console.log("gets printed once");
Campaign.updateResponse(_id, function (err, results2) {
if (err)
throw err;
else {
console.log("Gets printed once");
callback(); //tried this but gives callback already called error
}
}) // console.log(results);
}
})
}, function (err) {
console.log("Doesn't print");
callback();
})
You must use it like this:
//async.eachOfSeries(data, function (value2, val, callback) { => wrong
async.eachOfSeries(data, function (value2, callback) {
//
})
Thought I'd leave this here in case someone else hits this thread.
The problem is that on your optional callback at the end:
}, function (err) {
console.log("Doesn't print");
callback();
});
You're calling the iterator callback and not an outer callback.
In the context of your code you probably have your async inside other function which callback is the one you should call on your async's optional callback at the end. Or just don't use the optional function, but never let it go through your iterator callback after ending the loop.
You should also test for error, something like:
}, function(err){
if(err){
debug('Something went wrong in async: ' +err);
outerCallback(err, somethingIfitsthecase);
}else{
outerCallback(null, somethingIfitsthecase);
}
});
Check caolan's documentation as Parth Acharya recommended.
Thanks
Best regards
Pedro Velez Silva
It is supposed to work that way.
if an error occurs, which is happening in your case. It runs the final callback function that you've provided.
Link :- https://caolan.github.io/async/docs.html#eachOfSeries
A callback which is called when all iteratee functions have finished,
or an error occurs. Invoked with (err).
I had a similar dilemma and I solved it by adding a callback in the async param and calling it at the end of the method as shown below.
async.eachOfSeries(data, async (item, index, callback: any) => {
// method body
callback();
})

nodejs async two arrays and mongoose find

I am trying to use async module on my nodejs application with not lucky.
Suppose i have the following:
/**
* parents=['parent1Template','parent2TEmplate',...]
* children=[[{id: 'child1Parent1'}{id: 'child2Parent1'}],[{id: 'child1Parent2"}{id: 'child2Parent2'}],...]
*
*/
function createTemplate(parents,children){
var final=[]
async.each(Object.keys(parents), function(item,done){
if(children[item].length!==0) addChildsByParent(parents[item],children[item], function (result) {
final.push(result);
});
done();
});
console.log("Final results: "+final);
return final;
}
function addChildsByParent (parent,childs,callback){
var template=[];
//some operations..
async.each(childs,function(child){
Children.findone({"_id": child.id}, function (err,ch)){
template.push(ch);
}
});
return callback(template)
}
I need to get in final all results when all operations have finished.
I have seen also functions as parallel and waterfall on async module but the main problem is that i need to work always with two arrays and do the query when i get the single value.
What's the best way, maybe something like this?
async.waterfall([
each()...
async.waterfall([
each()...
])
])
I would use async map instead of each to build the response array using the map callback.
Also, I would use async parallel instead of waterfall to improve speed, since operations don't depend on each other and can be executed in parallel.
async.parallel({
final : function(next) {
async.map(Object.keys(parents), function(item,done){
if(children[item].length!==0) addChildsByParent(parents[item],children[item], function (result) {
done(null, result);
});
}, next);
},
template : function(next) {
async.map(childs, function(child, done) {
Children.findone({"_id" : child.id}, function (err, ch) {
done(err, ch);
});
});
}
}, function(error, results){
if (!error) {
console.log(results);
// This will be {final:[], template:[]}
}
});

async.parallel() - last function not being called

For some reason the 'yyyyyyyyy' string is never printed when I use async.parallel() as per below. Why is this? I thought that the last function would be called once the other two have been called.
var async = require('async');
async.parallel([
function() {
console.log('xxxxxxxxxxx');
},
function() {
console.log('ccccccccccc');
}
], function(err, results){
console.log('yyyyyyyyy');
});
Every function passed in the first parameter to async.parallel should take a callback that it calls when its done so async knows that it has completed:
var async = require('async');
async.parallel([
function(callback) {
console.log('xxxxxxxxxxx');
callback();
},
function(callback) {
console.log('ccccccccccc');
callback();
}
], function(err, results){
console.log('yyyyyyyyy');
});
If an error happens in one of the functions, it should call the callback with
callback(err);
so that async knows an error has occurred and it'll immediately call the last function.

Should I be using process.nextTick

I'm trying to get my head around when to use process.nextTick. Below I'm using async library to control my code flow and was wondering if I should be calling nextTick in the end callback or not.
async.parallel([
function (callback) {
// do something
callback(data);
},
function (callback) {
// do something
callback(data);
}
],
// callback
function (data) {
process.nextTick(function () {
// do something
});
});
Without knowing exactly what your 'do something' is, I don't see any reason that you'd need to use nextTick in this situation. You use nextTick when you have reason to defer execution of a function to the next iteration of the event loop. You might want to read Understanding process.nextTick for more detail.
Also, note that async's parallel task completion callbacks take arguments err, data, so you should be doing:
async.parallel([
function (callback) {
// do something
callback(null, data);
},
function (callback) {
// do something
callback(null, data);
}
],
// callback
function (err, data) {
if (err) throw err;
// do something
});
The major difference being that the final callback is invoked immediately if one of the parallel tasks returns an error (calls callback with a truthy first argument).
My experience is that for async.parallel and other similar functions to work correctly, that you need to make all tasks definitely asynchronous; I love the async lib and it's my #1 choice over promises etc, but there can be some weird behavior if you don't force tasks to be async.
See here:
https://github.com/caolan/async#common-pitfalls-stackoverflow
so it should be:
async.parallel([
function(cb){
process.nextTick(function(){
doSomePotentiallySyncThing(cb);
});
},
function(cb){
process.nextTick(function(){
doSomePotentiallySyncThing(cb);
});
},
function(cb){
definitelyAsync(cb); // if it's **definitely** async, then we don't need process.nextTick
}
], function complete(err, results){
// we are in the final callback
});
I am 99% sure about this.

Node.js - Using the async lib - async.foreach with object

I am using the node async lib - https://github.com/caolan/async#forEach and would like to iterate through an object and print out its index key. Once complete I would like execute a callback.
Here is what I have so far but the 'iterating done' is never seen:
async.forEach(Object.keys(dataObj), function (err, callback){
console.log('*****');
}, function() {
console.log('iterating done');
});
Why does the final function not get called?
How can I print the object index key?
The final function does not get called because async.forEach requires that you call the callback function for every element.
Use something like this:
async.forEach(Object.keys(dataObj), function (item, callback){
console.log(item); // print the key
// tell async that that particular element of the iterator is done
callback();
}, function(err) {
console.log('iterating done');
});
async.each is very useful and powerful function which is provided by Async Lib .it have 3 fields
1-collection/array
2- iteration
3-callback
the collection is referred to the array or collection of objects and iteration is refer to the each iteration and callback is optional .
if we are giving callback then it will return the response or say result which you want to show you in the frontend
Applies the function iteratee to each item in coll, in parallel. The iteratee is called with an item from the list, and a callback for when it has finished. If the iteratee passes an error to its callback, the main callback (for the each function) is immediately called with the error.
Note, that since this function applies iteratee to each item in parallel, there is no guarantee that the iteratee functions will complete in order.
exapmle-
var updateEventCredit = function ( userId, amount ,callback) {
async.each(userId, function(id, next) {
var incentiveData = new domain.incentive({
user_id:userId,
userName: id.userName,
amount: id.totalJeeneePrice,
description: id.description,
schemeType:id.schemeType
});
incentiveData.save(function (err, result) {
if (err) {
next(err);
} else {
domain.Events.findOneAndUpdate({
user_id: id.ids
}, {
$inc: {
eventsCredit: id.totalJeeneePrice
}
},{new:true}, function (err, result) {
if (err) {
Logger.info("Update status", err)
next(err);
} else {
Logger.info("Update status", result)
sendContributionNotification(id.ids,id.totalJeeneePrice);
next(null,null);
}
});
}
});

Resources