Using NodeJS, Express, Socket.io & node-mysql on a server at the moment. Currently having a problem with one of the functions on the server not returning any data at all. I'm at my ends wit trying to figure this out.
Function Code;
It is supposed to return "c", but is not working. The console.log is actually showing the ID and username.
function LOGIN_USER(a,b) {
// a = username
// b = password
var c = [];
connection.query("SELECT ID FROM GAME_PLAYER WHERE USR = '" + a + "' AND PWD = '" + b + "'", function(err,rows,field) {
if (err) throw err;
for (var i in rows) {
c.ID = rows[i].ID;
c.USR = a;
}
console.log(c.ID + " " + c.USR);
return c;
});
}
Other code.
socket.on('login user', function(data) {
var c;
c = LOGIN_USER(data.username,data.password);
console.log(c.ID,c.USR);
});
After this console.log is where my nodeJS server crashes. Saying it can't display undefined etc.. etc.
Can't for the life of me figure this out, any help is most appreciated!! :)
The MySQL query is asynchronous, so you cannot use a return value in it. In asynchronous programming, you must use a callback, because a return statement will stop execution:
function LOGIN_USER(a, b, callback) {
// a = username
// b = password
var c = [];
connection.query("SELECT ID FROM GAME_PLAYER WHERE USR = '" + a + "' AND PWD = '" + b + "'", function (err, rows, field) {
if (err) throw err;
for (var i in rows) {
c.ID = rows[i].ID;
c.USR = a;
}
console.log(c.ID + " " + c.USR);
callback(c);
});
}
And then this is how you'd use it:
socket.on('login user', function(data) {
LOGIN_USER(data.username, data.password, function(c) {
console.log(c.ID, c.USR);
});
});
When you use a return statement in a callback function, it acts as if you used return;, which in turn just stops the execution of a function. This is how the callback is working:
You are passing values to a function, as well as another function:
var func = function() {
// do something
};
LOGIN_USER(a, b, func);
When the user login has completed, the login function will call the function that was passed to it:
function LOGIN_USER(a, b, callback) {
// do some work
callback();
};
So you passed func() to LOGIN_USER(), and LOGIN_USER() called func() when it completed.
Related
I want to add have nested DB query inside a eachOf loop which should be synchronous. Tried so many combinations and which but nothing works for inside of foreach loop.
async.eachOf(nc.virtual_devices, function (vd) {
///////// This code work fine /////////////
var domain = extractDomain(vd.api_url);
vd.raw_api_ip = vd.api_ip;
vd.api_ip = getProxiedPath(vd.api_ip);
vd.raw_api_url = vd.api_url;
vd.api_url = nconf.get('PROXIED_PATH_SCHEME') + vd.api_ip + vd.api_url.split(domain)[1];
// Path to websocket notifications
vd.ws_url = nconf.get('PROXIED_PATH_SCHEME') + vd.api_ip + vd.notification_base_uri;
//// THIS CODE IS NOT FINE //////////////
if (nc.type === 'XXX'){
var promise = new Promise (function (resolve,reject) {
console.log("********XX VD TYPE **********");
console.log(JSON.stringify(vd));
console.log("VD ID VALUE IS ", vd.id);
var newID = (vd.id).replace(/\d_/, "");
console.log("VD ID VALUE IS ", newID);
var _idofSubgroup;
var labeltoSearch = nc.type + ' ' + nc.version;
pattern = "/^" + newID + "/i";
test = _idofSubgroup;
pattern = newID;
console.log(pattern);
db.collection('subgroups').findOne({label: labeltoSearch}, function (err, result) {
console.log(result._id);
_idofSubgroup = result._id;
db.collection('exploreposts').find({subgroup: result.id_}, {title: {"$regex": pattern}}).toArray(function (err, results) {
console.log(results);
})
});
})
}
});
Tried with promise inside it but that also in pain.
This is my tried code which is not working fine. Any suggestion would be appreciated., as simply said i have been stuck in callback hell
async.eachOf(nc.virtual_devices, function (vd) {
///////// This code work fine /////////////
var domain = extractDomain(vd.api_url);
vd.raw_api_ip = vd.api_ip;
vd.api_ip = getProxiedPath(vd.api_ip);
vd.raw_api_url = vd.api_url;
vd.api_url = nconf.get('PROXIED_PATH_SCHEME') + vd.api_ip + vd.api_url.split(domain)[1];
// Path to websocket notifications
vd.ws_url = nconf.get('PROXIED_PATH_SCHEME') + vd.api_ip + vd.notification_base_uri;
//// THIS CODE IS NOT FINE with promises also //////////////
if (nc.type === 'XXX'){
var promise = new Promise (function (resolve,reject) {
console.log("********XX VD TYPE **********");
console.log(JSON.stringify(vd));
console.log("VD ID VALUE IS ", vd.id);
var newID = (vd.id).replace(/\d_/, "");
console.log("VD ID VALUE IS ", newID);
var _idofSubgroup;
var labeltoSearch = nc.type + ' ' + nc.version;
pattern = "/^" + newID + "/i";
test = _idofSubgroup;
pattern = newID;
console.log(pattern);
db.collection('subgroups').findOne({label: labeltoSearch}, function (err, result) {
console.log(result._id);
_idofSubgroup = result._id;
resolve ({id_:_idofSubgroup,pattern1 : pattern});
})
});
promise.then (function(result) {
console.log(result.id_);
console.log(result.pattern1);
db.collection('exploreposts').find({subgroup: result.id_}, {title: {"$regex": result.pattern1}}).toArray(function (err, results) {
console.log(results);
})
},function (err){
console.log (err);
})
}
});
It doesn't seem you need to use async.eachOf, but async.each() or async.eachSeries().
This is untested but it would look something like
async.eachSeries(nc.virtual_devices, function iteratee(vd, cb) {
console.log('calling iteratee()')
var domain = extractDomain(vd.api_url);
vd.raw_api_ip = vd.api_ip;
vd.api_ip = getProxiedPath(vd.api_ip);
vd.raw_api_url = vd.api_url;
vd.api_url = nconf.get('PROXIED_PATH_SCHEME') + vd.api_ip + vd.api_url.split(domain)[1];
// Path to websocket notifications
vd.ws_url = nconf.get('PROXIED_PATH_SCHEME') + vd.api_ip + vd.notification_base_uri;
// skip the rest if type is XXX;
// you need to explicitedly call the original callback i.e. cb
// note the use of return to prevent execution of the rest of the code
if (nc.type !== 'XXX')
return cb(null); // or cb();
console.log("********XX VD TYPE **********");
console.log(JSON.stringify(vd));
console.log("VD ID VALUE IS ", vd.id);
var newID = (vd.id).replace(/\d_/, "");
console.log("VD ID VALUE IS ", newID);
// I have no idea what is going here
var _idofSubgroup;
var labeltoSearch = nc.type + ' ' + nc.version;
var pattern = "/^" + newID + "/i";
test = _idofSubgroup;
pattern = newID;
console.log(pattern);
// we're going to use waterfall here as you have 2 async operations, where one is dependent on the other
async.waterfall([
function getSubgroup(cb1) {
console.log('calling getSubgroup')
db.collection('subgroups').findOne({ label: labeltoSearch }, function (err, subgroup) {
// if an error occurs, stop waterfall-loop
// you do this by passing the error in the callback
// again note the use of return here to prevent execution of the rest of the code
if (err) return cb1(err);
// pass the data to the next task
cb1(null, subgroup, pattern);
});
},
function getPosts(subgroup, pattern, cb2) {
// we will only get here if the last task ^ went through
console.log('calling getPosts')
db.collection('exploreposts').find({ subgroup: subgroup._id, title: { $regex: pattern }}).toArray(function (err, posts) {
// if an error occurs, stop waterfall-loop
if (err) return cb2(err);
// do something with posts
console.log('posts', posts);
// otherwise, keep going
// since there are no more waterfall-tasks, waterfall ends
cb2();
});
}
], function (err) {
console.log('waterfall() done');
// if an error occurred during the waterfall-loop, it will come down here
// we will let the original callback i.e. cb deal with this error though
if (err) return cb(err);
// otherwise we're done
// we will let the original callback know everything went well by calling it without any error
cb();
});
// you could have also simply do
// ], cb);
}, function (err) {
console.log('eachSeries() done');
// handle any error that came
console.log(err);
// send response
});
I purposely name the variables and functions so that you get an idea.
Follow the logs if there are any issues.
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
I want to store the return values from functions to variable and use them after that but javascript doesn't wait for the function so when the code contiues it seems to be undefined
NOT DUPLICATE IM NOT TALKING ABOUT CALLBACK
Here's the code:
function register (name,user,pass)
{
var userex = checkUserExistance(user);
var nameex = checkNameExistance(name);
var globalex = nameex || userex;
var done = false;
if (!(globalex)) {
connection.query("INSERT INTO users (`name`,`user`,`pwd`) VALUES ('" + name + "','" + user + "','" + pass + "')", function (err, rows, fields) {
if (!err) {
done = true;
} else {
var today = new Date();
console.log(today.toGMTString());
console.log(err);
}
return { "ex": {"user":userex,"name":nameex}, "done": done };
});
}
}
Seems to be a missing closing bracket.
function register (name,user,pass)
{
...
if (!(globalex)) {
connection.query("INSERT INTO users (`name`,`user`,`pwd`) VALUES ('" + name + "','" + user + "','" + pass + "')", function (err, rows, fields) {
if (!err) {
done = true;
} else {
var today = new Date();
console.log(today.toGMTString());
console.log(err);
}
// *** Returning from the anonymous function ***
return { "ex": {"user":userex,"name":nameex}, "done": done };
}); // *** End of anonymous function
} // *** end if ***
// Still inside the register() function here, no value returned.
Similar to this question : Return response from async call
Except that the call is within a loop that calls multiple time the asynchronous function.
Specifically, how can the value of s be returned? This code returns undefined. This function is called within a for loop. The library used for ORM is Bookshelfjs. Thanks for the help.
function getUsernameFromDBAsync(userId) {
var s = "moo";
new Model.Users({
idUser: userId
})
.fetch()
.then(function(u) {
var prenom = u.get('firstName');
var nom = u.get('familyName');
s = prenom + " " + nom;
return s;
});
}
Your aren't really showing how you're doing the loop which makes it a little harder to guess what to recommend. But assuming .fetch().then() returns a promise, here's a general idea with standard ES6 promises built into node.js:
function getUsernameFromDBAsync(userId) {
var s = "moo";
return new Model.Users({
idUser: userId
}).fetch().then(function (u) {
var prenom = u.get('firstName');
var nom = u.get('familyName');
s = prenom + " " + nom;
return s;
});
}
var userIds = [...];
var promises = [];
for (var i = 0; i < userIds.length; i++) {
promises.push(getUsernameFromDBAsync(userIds[i]));
}
// now set up a .then() handler for when all the promises are done
Promise.all(promises).then(function(names) {
// process names array here
}, function(err) {
// process error here
});
If you are using the Bluebird promise library, you could do it a little bit more simply like this:
function getUsernameFromDBAsync(userId) {
var s = "moo";
return new Model.Users({
idUser: userId
}).fetch().then(function (u) {
var prenom = u.get('firstName');
var nom = u.get('familyName');
s = prenom + " " + nom;
return s;
});
}
var userIds = [...];
Promise.map(userIds, getUsernameFromDbAsync).then(function(names) {
// process names array here
}, function(err) {
// process error here
});
Var s is unnecessary. Simply return the "prénom nom" string from then's success callback.
function getUsernameFromDBAsync(userId) {
return new Model.Users({
idUser: userId
}).fetch().then(function (u) {
return u.get('firstName') + ' ' + u.get('familyName');
});
}
Your "loop" can be achieved with Array.prototype.map() to generate an array of promises, followed by Promise.all(promises).then(...), to receive and handle an array of names when all the promises have resolved.
var promises = userIds.map(function(userId) {
return getUsernameFromDBAsync(userId);
});
Promise.all(promises).then(function(names) {
// do something with `names`, which is an array of `prénom nom` strings.
}, function(err) {
// handler error, eg ...
console.error(error);
});
Or more succinctly :
Promise.all(userIds.map(getUsernameFromDBAsync)).then(function(names) {
// do something with `names`, which is an array of `prénom nom` strings.
}, function(err) {
// handler error, eg ...
console.error(error);
});
function add(post)
{
var word = new KeyWord({ keyword: post.keyword});
word.save(function (err, word)
{
if(err)
{
if(err.code==11000)
return post.keyword + ' is already added.';
}
else
return 'Added : ' + post.keyword;
});
}
When I am trying to read return value of add function it returns nothing.
And also when I am trying to put message in variable and return that from outside also give null value.
To put it simply, you can't. To get values from functions like these, you must use a callback:
function add(post, callback) {
var word = new KeyWord({keyword: post.keyword});
word.save(function(err, word) {
if (err) {
if (err.code==11000) callback(post.keyword + ' is already added.');
else callback('Added : ' + post.keyword);
}
});
}
You'd then use the function like this:
add(post, function(result) {
// return value is here
}
Consider the following code:
function dbTask(q) {
mysql = new MySQL();
mysql.host = sqlHost;
mysql.user = sqlUser;
mysql.password = sqlPassword;
mysql.query("USE stock");
return mysql.query(q, function(err, results, fields) {
if(err) {
console.log("MySQL Error: " + err + ", Query: " + q);
return false;
} else {
return results; //here
}
});
};
var r = dbTask("SELECT * FROM user;");
console.log(r);
Whereas, I want the results to be returned from the inner anonymous function when calling dbTask() in the second last line, I am getting different output which seems like some internal construct of the mysql library under use.
How can I get dbTask to return the results when called?
Since mysql.query is asynchronous, then you'll have to re-think your architecture.
Instead of having your function return true or false, you'll have to pass in handlers to be called if the query returned true or false.
Something like this:
function dbTask(q, success, failure) {
mysql = new MySQL();
mysql.host = sqlHost;
mysql.user = sqlUser;
mysql.password = sqlPassword;
mysql.query("USE stock");
mysql.query(q, function(err, results, fields) {
if(err) {
console.log("MySQL Error: " + err + ", Query: " + q);
failure(err, results, fields);
} else {
success(results, fields);
}
});
};
Which you'd call like this:
dbTask(q,
function(results, fields) { /* ... */ },
function(err, results, fields) { /* ... */ });
You can't because dbTask returns once the mysql.query call completes to initiate the query. So by the time mysql.query's callback is called, console.log(r) has already executed.
This is the crux of the asynchronous nature of node.js.
What you can do is have dbTask accept a callback parameter that the function calls once results is available so that it can be provided to the caller asynchronously.