I have the following code which isn't returning data properly.
app.post('/login',function(req,res){
sess=req.session;
var au = authme(req.body.name,req.body.pass, function(err,data) {
if(err) {
return 'error';
}
console.log(data);
return data;
});
if(au) {
sess.username = au.name;
}
res.end('done');
});
Data is passed all the way to console.log(data); but when I try to use in in the au statement, its returning undefined.
This is the classic async problem. authme is running asynchronously so the code isn't running simply from top to bottom.
var au = authme(req.body.name,req.body.pass, function(err,data) {
console.log('I am second!')
});
console.log('I am first!')
You need to restructure the code a bit to get the desired behavior.
app.post('/login',function (req,res) {
authme(req.body.name,req.body.pass, function(err, data) {
if (err) {
return 'error';
}
if (data) {
req.session.username = data.name;
}
res.end('done');
});
});
Probably the functional call to authme is asynchronous. Put your if statement in the callback of the function call, to assure it is always validated after the asynchronous function has completed execution.
app.post('/login',function(req,res){
sess=req.session;
(authme(req.body.name,req.body.pass, function(err,data) {
if(err) {
return 'error';
}
console.log(data);
if(data) {
sess.username = au.name;
}
}))();
res.end('done');
});
In Nodejs operations are asynchronous - in short it means that result is resolved later, you don't know exactly when, while code execution goes on, not waiting for it. The way to handle such call are the callbacks. More on that topic here and here.
So with your code you fall into that classical trap. This part of the code
var au = authme(req.body.name,req.body.pass, function(err,data) {
if(err) {
return 'error';
}
console.log(data);
return data;
});
is an asynchronous call, that means that this part
function(err,data) {
if(err) {
return 'error';
}
console.log(data);
return data;
}
is a callback that runs only when result is obtained. While this part
if(au) {
sess.username = au.name;
}
is executed immediately after var au = authme(req.body.name,req.body.pass) is done.
By that moment there is no au resolved so that is why you're getting this error.
In your case you should put au check into the callback:
authme(req.body.name,req.body.pass, function(err,data) {
if(err) {
return 'error';
}
if(au) {
req.session.username = au.name;
}
res.end('done');
});
Related
I create this small module to import in other node js modules.
However my callback function is giving me an error. "callback is not a function".
How can I make it work.
exports.saveConnection = function dao(action, callback){
pool.getConnection(function(err,conn){
if (err) {
console.log(err);
return callback('');
}
//create tables
var createTables = function(conn){
conn.release();
var rl = readline.createInterface({
input: fs.createReadStream('struct.sql'),
terminal: false
});
rl.on('line', function(chunk){
conn.query(chunk.toString('ascii'), function(err, sets, fields){
if(err){
console.log(err);
}else{
console.log("Table created");
}
});
});
console.log("Table created");
}
var findByPrimaryKey = conn.query("select * from user",function(err,rows){
conn.release();
if(err) {
console.log(err);
}
});
conn.on('error', function(err) {
console.log(err);
return;
});
callback(findByPrimaryKey);
});
};
When ever you are about to call callback you have to check if its a function or not. you can do that by following check
if (typeof(callback) === 'function') {
// call callback here
} else {
// just return because callback is not supplied
}
and when you call exports.saveConnection you have to supply callback as second param if you want to do something in that callback
I am running a cron job with node with mongodb as the database. I am trying to close db connection and exit the process once the curr_1 each loop has executed completely.
However the exit() is called while function_2 is being executed. I understand this is due to the callback and is async in nature.
How do I make sure exit is called only once the curr_1.each is complete?
Any solution without promises?
function function_1(obj){
var curr_1 = coll_1.find({})
curr_1.each(function(err, doc) {
function_2(doc)
});
exit(obj)
}
function function_2(obj) {
coll_2.findOne({}, function(err, document) {
dosomeprocess(obj)
})
}
function exit(obj) {
// Close connection
console.log('closing connection')
obj.db.close();
process.exit();
}
It's a job for Node async....
For example:
async.each(
curr_1, // the collection to iterate over
function(doc, callback) { // the function, which is passed each
// document of the collection, and a
// callback to call when doc handling
// is complete (or an error occurs)
function_2(doc);
},
function(err) { // callback called when all iteratee functions
// have finished, or an error occurs
if (err) {
// handle errors...
}
exit(obj); // called when all documents have been processed
}
);
Without using any library:
function function_1(obj, callback) {
var curr_1 = coll_1.find({})
curr_1.each(function(err, doc) {
callback(err, doc);
});
}
function function_2(err, obj) {
coll_2.findOne({}, function(err, document) {
dosomeprocess(obj)
exit(err, obj);
})
}
function exit(err, obj) {
// Close connection
console.log('closing connection')
obj.db.close();
process.exit();
}
function_1(obj, function_2);
Using async module
var async = require('async');
async.waterfall([
function function_1(callback) {
var curr_1 = coll_1.find({})
curr_1.each(function(err, doc) {
if (err) {
callback(err, null)
} else {
allback(null, doc)
}
});
},
function function_2(obj, callback) {
coll_2.findOne({}, function(err, document) {
if (err) {
callback(err, null);
} else {
dosomeprocess(obj)
callback(null, obj);
}
})
}
], function done() {
obj.db.close();
process.exit();
});
Simply give a condition in your loop using counter.
function function_1(obj){
var curr_1 = coll_1.find({})
var curr_1Length = curr_1.length;
var counter = 0;
curr_1.each(function(err, doc) {
++counter;
//Check condition everytime for the last occurance of loop
if(counter == curr_1Length - 1){
exit(obj)
}
function_2(doc)
});
}
Hope it helps :)
I want to do async call from my getData function to getImage function but i am unable to get return data from getImage().Since the getData() does't wait for the completion of getImage(),as getImage() has further async db calls and therefore getData() always returns undefined.
What is the best way to do this instead doing nested callbacks?
var getData = function(id){
async.series([
function(callback){
var res = getImages(id);
callback(null, res);
}
],
// optional callback
function(err, results){
if (err) {
console.log("ERROR : " + err);
}else
{
console.log("Result: "+results);
}
});
}
var getImages = function(id){
async.series([
function(callback){
Image.find({id: id }).exec(
function(err, image) {
if (err) {
console.log(err);
callback(err, 0);
}else
{ console.log("Count: "+ image.length);
callback(null, image);
}
});
}
],
// optional callback
function(err, results){
if (err) {
console.log("ERROR : " + err);
}else
{
return results;
}
});
}
getData(1);
As you said you need to wait for getImages() to return, and you do that using promises.
Use any promise library, like q for instance:
var q = require('q')
...
var getImages = function(id){
var deferred = q.defer();
...
//do async logic that that evaluates some res obj you wish to return
db.find(..., function() {
deferred.resolve(res);
}
return deferred.promise;
}
Then, from getData(), you call it in the following matter:
getImages(id).then(
function(res) {
callback(null, res);
},
function(err) {
console.log("error:" + err);
}
);
As you are already using async - just use the waterfall functionality: https://github.com/caolan/async#waterfalltasks-callback
This way you will be able to run functions one after another and wait for the previous to finish, while still getting it's return value.
I'm having an annoying as hell problem with 'Error: Can't set headers after they are sent.' in Express. This code originally worked using Restify rather than Express and I have been having this problem in one form or another since converting it.
The code makes 2 asynchronous requests to another API (edited out) and merges the results into a single JSON before storing it in MongoDB.
Any insight would be appreciated as I have tried all I can think of and have no idea why the same function would work in Restify and not Express with the appropriate changes.
Please don't comment on the Pyramid of Doom, I know it's not ideal, but that's not the focus here ;)
app.post('/rest/test', jsonParser, /*keycloak.protect(),*/ function (req, res, next) {
var requestObj = req.body;
try {
/* run async requests in parallel */
async.parallel([
function asyncReqV3(callback) {
request.post(reqUrl1, option_v3, function(err, response, body) {
if(err) {
console.log(err);
callback(true);
return;
} else {
callback(false, body);
}
});
},
/* v4 async request */
function asyncReqV4(callback) {
request.post(reqUrl2, option_v4, function(err, response, body) {
if(err) {
console.log(err);
callback(true);
return;
} else {
callback(false, body);
}
});
},
],
/* Collate results and send */
function collateResults(err, results) {
if(err) {
console.log(err);
return res.status(500).send("Server Error");
} else {
/* Merging results */
var hash = new Map();
results[0].body.krResult.forEach(function(obj) {
hash.set(obj.word, obj);
});
var final = results[1].body.data.map(function(obj) {
return Object.assign(hash.get(obj.word) || {}, obj);
});
var final_results = final.slice(0, 250).map(function(obj) {
return {
thing1: obj.something,
thing2: obj.somethingElse
}
});
/* Store results in DB */
db.results.insert({
request: requestObj,
response: final_results
});
res.status(200).send(final_results);
}
});
}
catch(e) {
console.log(e);
res.status(500).send({});
}
return next();
});
At the end of your route callback, remove:
return next();
You don't need it here and this line will always be executed before the async.parallel is done (collateResults in your code). You're quite likely sending a response in the subsequent routes and then again after your two requests are done.
I've got following code now:
exports.listByUser = function(req, res) {
Attack.find({user: req.user._id}, function(err, attacks) {
if(err)
return next(err);
for(var i in attacks) {
attacks[i].evaluateFight();
}
res.json(attacks);
});
};
the main problem is that attacks[i].evaluateFight() is called asynchronously, I want to transform it to make sure that [i-1] iteration is done ... and finally call res.json(attacks). I think, it can be done with async, but I don't know how :( Something like this should work, but how can I call attacks.method?
async.eachSeries(attacks, function (callback) {
//something??
callback();
}, function (err) {
if (err) { throw err; }
res.json(attacks);
});
You can leverage async whilst method call to implement the same. However, there is question I have about the callback of evaluateFight because if it is executed asynchronously then there has to be some callback associated with it which will notify if the previous call is succeeded.
The example code can be as follows assuming evaluateFight returns a callback when completed -
exports.listByUser = function(req, res) {
Attack.find({user: req.user._id}, function(err, attacks) {
if(err)
return next(err);
var attacksLength = attacks.length;
var count = 0;
async.whilst(function () {
return count < attacksLength;
},
function (callback) {
attacks[count].evaluateFight(function(err, result){
count++;
callback();
}); // assuming it returns a callback on success
},
function (err) {
// all the iterations have been successfully called
// return the response
res.json(attacks);
});
};