async each callback is called before iteration - javascript

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);
));

Related

Why async.forEach callback is never getting called?

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

node.js wait for initialize variable before load other function

request('GET', url_ws).done((res) => {
if (res.statusCode==200) {
parseString(res.getBody(),{explicitArray:false}, function (err, result) {
pdfAnnotations=result['root']['element'];
console.log(pdfAnnotations);//show value//second
});
}
});
console.log(pdfAnnotations);//display "undefined"//first
fn_work(pdfAnnotations)
Hello, i have to work with variable loaded from web service, but when my function starts, variable is 'undefined'
You need to call your function after parseString() is done:
request('GET', url_ws).done(res => {
if (res.statusCode == 200) {
parseString(res.getBody(), { explicitArray: false }, function (err, result) {
const pdfAnnotations = result['root']['element']
doSomething(pdfAnnotations)
})
}
})
this is normal because the code is executed asynchronosly, it makes the request and then executes fn_work right after that, while fetching data from url_ws , then when it gets the data, it moves on to ParseString and so on,
the easy way is to move fn_work(pdfAnnontaions) inside the callback of the ParseString like so
request('GET', url_ws).done((res) => {
if (res.statusCode==200) {
parseString(res.getBody(),{explicitArray:false}, function (err, result) {
pdfAnnotations=result['root']['element'];
fn_work(pdfAnnotations);
});
}
});
i would recommend using promises or async/await , check these out :
https://blog.risingstack.com/mastering-async-await-in-nodejs/
https://www.valentinog.com/blog/http-requests-node-js-async-await/#Making_HTTP_requests_with_Nodejs_the_request_module

My callbacks are wrong - I am returning my response to my error object - Nodejs

I am trying to learn node and understand how callbacks are working. I am doing this by trying to use the async lib. I am trying to hit my db with 2 separate calls and use the async lib to let me know when my object is ready to build. Here is my aysnc code:
async.parallel({
one: function(callback) {
getUser(id, callback);
},
two: function(callback) {
getUserServices(id, callback);
}
}, function(err, results) {
if(err) {
console.log(err);
new Error();
}
res.json(result);
});
Here are what my functions look like where I am calling the db. There are both basically the same function:
var getUser = function(id, callback) {
var query = client.query('SELECT * FROM USERS WHERE USER_ID=$1', [id]);
query.on('row', function(row, result) {
result.addRow(row);
});
query.on('end', function(result) {
callback(result);
});
};
My code hits the db and returns the user, but when it goes back up to the async code the user is in the err object. What am I doing wrong? How do I properly set up callbacks?
As pointed by damphat, your code should be
//additionally, handle errors
query.on('error', function(err){
callback(err) // The first argument to callback should be an error object
})
query.on('end', function(result){
callback(null, result) //passing null error object
})

node.js async.series is that how it is supposed to work?

var async = require('async');
function callbackhandler(err, results) {
console.log('It came back with this ' + results);
}
function takes5Seconds(callback) {
console.log('Starting 5 second task');
setTimeout( function() {
console.log('Just finshed 5 seconds');
callback(null, 'five');
}, 5000);
}
function takes2Seconds(callback) {
console.log('Starting 2 second task');
setTimeout( function() {
console.log('Just finshed 2 seconds');
callback(null, 'two');
}, 2000);
}
async.series([takes2Seconds(callbackhandler),
takes5Seconds(callbackhandler)], function(err, results){
console.log('Result of the whole run is ' + results);
})
The output looks like below :
Starting 2 second task
Starting 5 second task
Just finshed 2 seconds
It came back with this two
Just finshed 5 seconds
It came back with this five
I was expecting the takes2Second function to finish completely before the takes5Second starts.
Is that how it is supposed to work. Please let me know.
And the final function never runs. Thanks.
Not quite. You are executing the functions immediately (as soon as the array is evaluated), which is why they appear to start at the same time.
The callback passed to each of the functions to be executed is internal to the async library. You execute it once your function has completed, passing an error and/or a value. You don't need to define that function yourself.
The final function never runs in your case because the callback function that async needs you to invoke to move on to the next function in the series never actually gets executed (only your callbackHandler function gets executed).
Try this instead:
async.series([
takes2Seconds,
takes5seconds
], function (err, results) {
// Here, results is an array of the value from each function
console.log(results); // outputs: ['two', 'five']
});
James gave you a good overview of async.series. Note that you can setup anonymous functions in the series array and then call your actual functions with parameters
var async = require('async')
var param1 = 'foobar'
function withParams(param1, callback) {
console.log('withParams function called')
console.log(param1)
callback()
}
function withoutParams(callback) {
console.log('withoutParams function called')
callback()
}
async.series([
function(callback) {
withParams(param1, callback)
},
withoutParams
], function(err) {
console.log('all functions complete')
})
My preferred way to create the async series is using operational array as follow;
var async = require('async'),
operations = [];
operations.push(takes2Seconds);
operations.push(takes5seconds);
async.series(operations, function (err, results) {
// results[1]
// results[2]
});
function takes2Seconds(callback) {
callback(null, results);
}
function takes5seconds(callback) {
callback(null, results);
}
async.series
([
function (callback)
{
response=wsCall.post(user,url,method,response);
console.log("one");
callback();
}
,
function (callback)
{
console.log("two");
//console.log(response);
callback();
}
]
,
function(err)
{
console.log('Both a and b are saved now');
console.log(response);
});
In async.series,all the functions are executed in series and the consolidated outputs of each function is passed to the final callback. e.g
var async = require('async');
async.series([
function (callback) {
console.log('First Execute..');
callback(null, 'userPersonalData');
},
function (callback) {
console.log('Second Execute.. ');
callback(null, 'userDependentData');
}
],
function (err, result) {
console.log(result);
});
Output:
First Execute..
Second Execute..
['userPersonalData','userDependentData'] //result

Waterfall method for async.js hanging when calling mongoose save method

I'm trying to use the async waterfall method but when it gets to one of the functions, it hangs. I suspect it's because the save() operation is too slow for the execution context, but that's why I was starting to use async's waterfall, so I can wait for the value returned until it goes to the next function in the series (passing along the proper data with it which would be the counted in my case below).
// In my user controller:
async.waterfall([
function(callback) {
getSubmission(id, function(submission) {
if (submission) {
callback(null, submission);
}
});
},
function(submission, callback) {
var submissionId = submission._id;
getViews(submissionId, ip, function(count) {
if (count) {
callback(null, count, submissionId);
}
});
},
// Those top two functions work perfectly passing what
// I need to this one which is where I'm having trouble
function(views, submissionId, callback) {
// addView is called because it is actually
// inserting a row in the db, but never returns from the caller
addView(submissionId, ip, function(added) {
// this callback doesn't fire
if (added) {
callback(null, added);
}
});
},
function(added, callback) {
console.log(added);
}
]);
This is what addView() is (also within user controller which is where the previous async.waterfall code also is in) :
var addView = function(submissionId, ip, callback) {
Submission.addView({
submissionId : submissionId,
ip: ip
}, function(err, counted) {
if (err) {
throw err;
}
if (counted) {
callback(counted);
}
});
};
This is what it's calling (inside my Submission model file) when it calls Submission.addView():
exports.addView = function(obj, fn) {
var ip = obj.ip,
submissionId = obj.submissionId,
submissionView = new SubmissionView(obj);
// it gets to this point
submissionView.save({
ip : ip,
submission_id : submissionId
}, function(err, counted) {
fn(err, counted);
});
};
Whenever async "hangs", it's usually because a callback hasn't been called.
You need to make sure that you call the callback in all code paths. I would also recommend that you reserve the first parameter of any async callback to be an error, even if you don't use it as that is the pattern used throughout node.js. Some modules rely on this pattern. e.g. domains.
If you make the below change, then I would expect some error to pop up somewhere:
getSubmission(id, function(submission) {
if (submission) {
callback(null, submission);
}
});
should be something like this:
getSubmission(id, function(err, submission) {
if(err){
return callback(err);
}
if (!submission) {
return callback('no submission found');
}
callback(null, submission);
});

Categories

Resources