Why async.forEach callback is never getting called? - javascript

In Below code, I am using forEach and in it, I am iterating over an array, and inside forEach I am calling another function while passing the parameter as callback, Now the thing is even I am calling this callback from the function, the forEach callback is never getting called
async.forEach(Array_Ids, function (item, callback){
sendPushNotif(item.mess, item.Ids, callback);
}, function(err) {
// EXECUTION NEVER COMING HERE
if(err) {
res.json({status_code : 200, message : "Correctly Hit the URL!"});
return next();
} else {
res.json({status_code : 200, message : "Correctly Hit the URL!"});
return next();
}
});
function sendPushNotif(mess, Ids, callback) {
sender.send(mess, { registrationTokens: Ids }, function(err, result) {
if(err) {
callback(null);
}
else {
console.log(null);
}
});
}

You only invoke callback() conditionally here:
function(err, result) {
if(err) {
callback(null);
}
else {
console.log(null);
}
}
If you want to suppress errors, you can replace the if/else with
callback(null);
If you want to propagate errors, you can replace the whole function expression with
callback

Related

Can someone explain how callbacks are invoked in Node.js please?

I understand callback functions conceptually, but I don't understand how they are understand in Node.js and am quite confused by the syntax. Can someone give me a simple explanation for each line of code which is running? The code works, but I don't understand why.
var removeById = function(personId, done) {
Person.findByIdAndRemove(personId, function(err, data) {
if(err) {
done(err);
}
done(null, data);
});
};
Line by line explanation.
Line 1 (assume)
var removeById = function(personId, done) {
done is the formal identifier for callback that you'll pass later when you call removeById function
Line 2
Person.findByIdAndRemove(personId, function(err, data) {
findByIdAndRemove expects 2nd parameter to be a function with two parameters, first err, this will hold error and 2nd data, this will hold data/result
Line 4
done(err)
Line 6
Call your callback with error
done(null, data)
call your callback with first parameter as null (probably intended to signal there is no error) and data which would hold the data/result
Extra note:
The callback you pass to removeById should also (preferably, if you're not doing anything else with it) expect 2 parameters, same as callback passed to findByIdAndRemove
The Person.findByIdAndRemove is basically something like :
Person.findByIdAndRemove = function(personId, callback) {
// The code is executed
// call function on error | success
callback(err, data);
};
The callback you want to execute should be something like:
const done = function(err, data) {
if(err) {
console.log(err);
}
console.log(data);
}
Your code :
var removeById = function(personId, done) {
Person.findByIdAndRemove(personId, function(err, data) {
if(err) {
done(err);
}
done(null, data);
});
};
Usage:
removeById(3, done);

Callbacks and Async functions

How can I integrate Discovery with Conversation? I'm using NodeJS, but having problems because I want the conversation results to come after querying my data collection. I'm trying to use callbacks but no luck yet. I could use async, but could I use simple callbacks in this case? Help appreciated, thanks!
function updateMessage(res, data) {
if (!data.output) {
data.output = {};
} else {
/* THIS CODE RETURNS CONVERSATION DATA FIRST, CAUSING THE DISCOVERY QUERY
TO BECOME UNDEFINED */
if (data.context.callDiscovery === true) {
//Query collection
Discovery.query(params, function(error, results) {
data.output.text = "Getting what you need";
//Set output graph card
data.output.graph = {
title: results.title,
url: result.url,
description: results.passage_text
};
return results;
});
}
return data;
}
}
You are mixing sync and async operations.
Here is an example of a function returning synchronously:
function (options) {
if (options.flag) {
return "Flag is set";
} else {
return "Flag is not set";
}
}
This is an example of a function returning asynchronously:
function (options, done) {
Discovery.query({options}, function (err, results) {
if (err) return done(err);
return done(null, results);
});
}
However, it's not recommended to return a function accepting callback immediately based on a condition or perform an async operation and then return. If your function does not take a callback in and does not call that callback when the async operation is finished, your function will be done executing before the async operations is finished. For example:
function mixedUp(options) {
Discovery.query({options}, function (err, results) {
if (err) return err;
return results;
});
return 'default value';
}
This will always return default value, because before the Discovery request is finished, your function has returned.
You should make your function accept a callback or a done parameter, which in idiomatic node, is the last argument of your function. function (options, moreOptions, done/callback/cb) should be signature of your function. Then, your function should call that callback function when you want to perform an action.
function updateMessage(res, data, done) {
if (!data.output) {
data.output = {};
return done(null, data);
} else {
/* THIS CODE RETURNS CONVERSATION DATA FIRST, CAUSING THE DISCOVERY QUERY
TO BECOME UNDEFINED */
if (data.context.callDiscovery === true) {
//Query collection
Discovery.query(params, function(error, results) {
data.output.text = "Getting what you need";
//Set output graph card
data.output.graph = {
title: results.title,
url: result.url,
description: results.passage_text
};
return done(null, results);
});
} else {
return done(null, data);
}
}
}

Node.js Getting the error TypeError: callback is not a function

I can't figure out how to pass the object result back to the function. I am trying to do a callback but it's not working. What am I doing wrong? Does anyone know how to pass a variable from a child function to a parent function?
I also can't seem do do that as well.
findOrCreate(fb_response, function(error, result) {
if (error) {
res.serverError(error);
}
return res.send(result);
});
// If no user create new user
function findOrCreate(fb_response, callback) {
Users.findOne({
email: fb_response.email
}).exec(function(error, result) {
if (error) {
return callback(error, null);
}
// if user does not exist
else if (!result) {
//create a new user
createUser(fb_response, function(error, result) {
if (error) {
return callback(error, null);
}
// re-start the find or create function
return findOrCreate(fb_response, null);
}); // end of create new user function.
} // end of - else if (!record)
else if (result) {
return callback(null, result) // this is the part that I am getting wrong
}
});
}
the problem is mainly with your
return findOrCreate(fb_response, null);
as you pass the call the callback function as null and never checks for it to be non null when executing it. Try changing it to
return findOrCreate(fb_response, callback);

Identify Closure Memory Leak

I'm currently writing a simple api where you post an array (length = 200) and since each element in the array needs to do 1-2 look up requests, I'm using the async library to control the flow of things. I'm using node 0.12.5 & Express.
router.post('/data', function(req, res, next) {
var cloudDB = db.cloudant.use('events');
var tempStorage = {"docs": []};
// This each loop is to make sure all events get iterated through before submitting response
async.each(req.body, function(singleEvent, loopCallback) {
// this should be async waterfall or something better to organize it
async.waterfall(
[
function(callback) { // get user data from db
db.getUserInfo(singleEvent.email, function (error, dbResponse) {
if(error) { // Houston, we have a problem
return callback(error);
}
return callback(null, dbResponse);
})
},
function(dbResponse, callback) { // decide what to do about results
if(!dbResponse) { // we were unable to get the user from DB
db.searchForUser(singleEvent.email, function (err, searchResponse) {
if(err)
return callback(err);
else
return callback(null, JSON.parse(searchResponse));
})
}
else {
return callback(null,JSON.parse(dbResponse));
}
},
function(userInfo, callback) { // combine data into proper logic
callback(null,combineEventAndUserData(singleEvent,userInfo));
}
],
function (err, result) {
// User event has been processed, so if there are no errors, lets add it to the queue
if(err) {
console.log(err);
}
else {
tempStorage.docs.push(result);
}
loopCallback(); // We're done with this singleEvent
}
)
}, function(err) { // function gets called when all singleEvents have been looped through
console.log("Finished each");
if(err) {
res.status(500).send(err);
}
else {
cloudDB.bulk(tempStorage, function(err, body) {
if(!err) {
res.status(200).send(body);
}
else {
res.status(500).send(err);
}
})
}
});
});
So, this code works! However... (sniff sniff), I seem to have created a memory leak. I have taken a look at both memwatch-next and heapdump, and all I've been able to tell was that 'arrays' keep growing when I look at the heap dump.
I don't know why, but I have a suspicion that this might have something to do with closures and how I'm storing the items generated from each of the waterfalls and perhaps the tempStorage.docs is not being released? Am I storing the tempStorage in the correct way? Or should I change how I do that?

async each callback is called before iteration

i have the following routing function:
router.route('/api/teamUsersWithStat/:team_id')
.get(function (req, res) {
var user_stat = academy_team_user_stat.build();
user_stat.usersByTeam(req.params.team_id, function (result) {
if (result) {
async.each(result, function () {
var i = 0;
user_stat.findModulesTaken(res.user_id, res.team_id, function (modules) {
result[i].modules = modules;
i++;
});
}, res.json(result))
} else {
res.status(401).send("Team not found");
}
}, function (error) {
res.send("Team not found");
});
});
as you can see im using the async.each method to collect additional data to my existing array.
However the res.json(result) is called without it running the actual loop.
(i can tell this as in my javascript i am debugging the response).
So what am i doing wrong?
You're calling your res.json method straight away, you're also reinitializing i inside the loop so it's always 0.
Also, each requires a callback in order to procede to the next iteration.
The following is how I'd do it:
async.each(result, function (r, callback) {
user_stat.findModulesTaken(res.user_id, res.team_id, function (modules) {
result[result.indexOf(r)].modules = modules;
callback();
});
}, function(err) {
if(err)
return res.json(err);
res.json(result);
});
res.json(result) is called as a function, and therefore invoked immediately. To make sure res.json is invoked after the async.each(), you need to pass a function as callback:
async.each(result, function () {
...
}, function(err) {
if(!err) res.json(result);
));

Categories

Resources