This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 25 days ago.
I am new to express and socket io and I'm trying to build a simple multiplayer game
This is my server on connect code:
io.on('connection', function (socket) {
var characterID = socket.request._query['character'];
console.log("Character ID: " + characterID);
var characterData = null;
db.query(`SELECT * FROM characters WHERE id = ${characterID} LIMIT 1`, (err, result, fields) => {
if ( err ) throw err;
console.log("Retrieved Data", result, fields);
characterData = result[0];
});
console.log("Character Data", characterData);
});
The output have one extra line starting with "Retrieved data", but it doesn't even show, is the query not running at all?
I recommend you generate a function that returns the character and then pass it to a variable, considering the asynchrony
const getCharacterById = (characterID) => {
return new Promise((resolve, reject) => {
db.query(`SELECT * FROM characters WHERE id = ${characterID} LIMIT 1`, (err, result) => {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
};
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
How to properly return a result from mysql with Node?
(6 answers)
Closed 25 days ago.
This post was edited and submitted for review 25 days ago.
I' m building a email verification for my website in node.js and for it to work it changes a value in a mysql database, it has to return 1 or 0 if it works or doesn't work but the code doesn' t wait for the return and inmidiatly goes further even though I use async and await.
this is the code I used in the pages.js:
router.get("/verify-email", async (req,res) => {
var tokens = req.query.token
console.log(tokens)
const verified = await emailverification(tokens)
console.log("hello",verified)
if (verified == 1) {
res.sendFile('verifySuccess.html',{root: "./public"});
} else {
res.sendFile('verifyFail.html',{root: "./public"});
}
})
and this is the funciton it has to wait for:
const emailverification = async(token,req,res,next) => {
var tokens = token
console.log("hello",tokens)
db.query('SELECT * FROM users WHERE token = ?',[tokens], async(err, result) =>{
console.log("1")
if (err) throw err;
console.log(result)
if(result[0].verify == "0"){
console.log("2")
console.log(result[0].email)
if (result.length > 0) {
console.log("2.5")
var email = result[0].email
console.log(email)
console.log("2.75")
db.query('UPDATE users SET verify = 1 WHERE email = ?', email, async(err, result) => {
console.log(result[0])
console.log("3")
if(err) throw err
return 1
})
} else {
console.log("5")
return 0;
}
}else{
console.log("6")
return 0;
}
})
}
module.exports = emailverification;
I searched on goolge and here on stackoverflow and found a lot of stuff about this but it doesn't work in my code.
this is the source code: the source code
the follwing 2 questions:
how-do-i-return-the-response-from-an-asynchronous-call and how-to-properly-return-a-result-from-mysql-with-node don't help because those questions ar abour something else and not about the problem I have. because by my problem the code doesn' t return the stuff before contini=uing even though I use the async/awaint things like they do by these 2 questions
please don't mind all the logs I use them to see what runs and what doesn't,
you have to return like this.
const emailverification = async (req, res) => {
var tokens = req.tokens;
return db.query(
"SELECT * FROM users WHERE token = ?",
[tokens],
async (err, result) => {
if (err) throw err;
if (result[0].verify == 0) {
console.log(result[0].email);
if (result.length > 0) {
var email = result[0].email;
console.log(email);
console.log("2.75");
db.query(
"UPDATE users SET verify = 1 WHERE email = ?",
email,
async (err, result) => {
console.log(result[0]);
console.log("3");
if (err) throw err;
}
);
return res.status(200).send({ message: "true" });
} else {
var message = { status: "error", error: "email already verified" };
console.log("5");
return res.status(400).send({ message: "false" });
}
} else {
console.log(result);
console.log("6");
message = { status: "error", error: "email already verified" };
return res.status(400).send({ message: "false" });
}
}
);
};
module.exports = emailverification;
Simple Question: Why on earth is this undefining itself!?
const bot = new TelegramBot(config.ttoken, {
polling: true
});
console.log(bot) // WORKING AND DEFINED
con.query(`SELECT * FROM user WHERE token = "${token}"`, (err, rows) => {
if (err) throw err;
rows.forEach((row) => {
console.log(bot) // NOT WORKING AND UNDEFINED?
)}
});
why....
I'm having severe doubts that the code I'm writing is an efficient/best way to achieve my goal.
I have a promise which makes an SQL query, after it's completed I loop through an array and it's sub arrays+objects. Even if any of the subloops fail for any specific reason I want the inner loops to continue executing until the entire array has been looped through. Right now I have a "try/catch" hell which I doubt is the correct way to do this. I should however say that it works as expected, but how bad code is it?
new Promise((resolve, reject) => {
sqlConnection.execute(
'INSERT INTO pms (userId, message, conversationId) VALUES (?, ?, ?)',
[userid, receivedMsg, receivedConvId],
function(err, results) {
if (err) throw err;
resolve("DEBUG: PM from "+username+" into conv "+receivedConvId+" was sucessfully inserted to DB");
}
);
}).then(() => {
users.forEach(function(userobj, i, arr) {
try {
if (userobj.memberof.includes(receivedConvId)) {
let rcptUsername = userobj.username;
let rcptUserid = userobj.userid;
debug(rcptUsername+" is member of the group "+receivedConvId);
Object.keys(userobj.sessions).forEach(function(session) {
try {
userobj.sessions[session].forEach(function(wsConn) {
try {
debug("DEBUG: Broadcasting message to "+rcptUsername+" for connections inside session "+session);
wsConn.send(JSON.stringify(msgToSend));
} catch(err) {
errorHandler(err);
}
});
} catch(err) {
errorHandler(err);
}
});
}
} catch(err) {
errorHandler(err);
}
});
}).catch((err) => {
debug(err);
}).then(() => {
debug("INFO: Message broadcast finished");
});
The array I'm looping through could look like this:
[
{ username: 'Root',
userid: '1',
memberof: [ 1, 2, 3 ],
sessions:
{
pvkjhkjhkj21kj1hes5: [Array],
'4duihy21hkk1jhhbbu52': [Array]
}
},
{
username: 'Admin',
userid: '2',
memberof: [ 1, 2, 4 ],
sessions:
{
cg2iouoiuiou111uuok7: [Array],
sl1l3k4ljkjlkmmmmkllkl: [Array]
}
}
]
Grateful for any advice.
Assuming wsConn is a https://github.com/websockets/ws websocket - then the code you are using will only ever "detect" immediate errors anyway - any socket write failures will not be caught
You'll also be outputting "INFO: Message broadcast finished" before any of the wsConn.send have finished - because it's asynchronous
Fortunately .send has a callback, which is called back on errors or success once the send has completed - this solves both issues
Using promises is a good idea, except you haven't used promises for anything but the initial SQL execute, which is why you've ended up in nesting hell
I'm fairly confident (without your full code I can't be sure) that the following code will not only run, it has far less nesting
new Promise((resolve, reject) => {
sqlConnection.execute(
'INSERT INTO pms (userId, message, conversationId) VALUES (?, ?, ?)',
[userid, receivedMsg, receivedConvId],
(err, results) => {
if (err) {
return reject(err);
}
resolve("DEBUG: PM from " + username + " into conv " + receivedConvId + " was sucessfully inserted to DB");
}
);
}).then(() => {
const allConnectionsArray = users
.filter(({memberof}) => memberof.includes(receivedConvId)) // filter out any userobj we aren't going to send to
.map(({rcptUsername, rcptUserid, sessions}) => {
debug(rcptUsername + " is member of the group " + receivedConvId);
const userSessionsArray = Object.entries(sessions).map(([session, value]) => {
return value.map((wsConn, index) => {
return { wsConn, rcptUserid, rcptUsername, session, index };
})
});
return [].concat(...userSessionsArray); // flatten the array
});
const promises = [].concat(...allConnectionsArray) // flatten the array
.map(({ wsConn, rcptUserid, rcptUsername, session, index }) => {
debug("DEBUG: Broadcasting message to " + rcptUsername + " for connections inside session " + session);
return new Promise((resolve) => {
wsConn.send(JSON.stringify(msgToSend), err => {
if (err) {
return resolve({ rcptUserid, rcptUsername, session, index, err });
}
resolve({ rcptUserid, rcptUsername, session, index, err: false });
});
});
});
return Promise.all(promises);
}).then(results => {
/* results is an array of {
rcptUserid
rcptUsername
session
index //(index is the ordinal position in user.sessions array
err //(===false if success)
}
*/
debug("INFO: Message broadcast finished");
}).catch(error => {
// the only error caught here would be in the `return reject(err);` in the sql execute,
// because any failure in wsConn.send is a resolved promise (with an error property)
// unless I'm not seeing something obvious, they are the only possible places an error could be thrown anyway
});
This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 4 years ago.
I have some code like this:
let addUser = (req, res) => {
let user;
let message = "";
let status = 200;
bcrypt.hash(password, salt_rounds, (err, hash) => {
user = new user({
...
password: hash,
});
user.save(err => {
if(err) {
message = "No success";
status = 400;
} else {
message = "success";
}
});
res.status(status).json({
message: message,
});
});
};
However, the message variable is undefined when the response is sent. I've been searching for a while now and, unfortunately, haven't been able to find a solution similar to this problem.
Ultimately, what I would like is to be able to update the message, status, etc. variables within the bcrypt/.save closures. I have tried using callbacks and resolving promises which I'm assuming didn't work due to naivety. Regardless, any solution would be appreciated!
Note: I would not like to use any other libraries to solve this problem (which I really doubt is required in the first place)
Thanks in advance!
Change user.save into something that returns a Promise, and then call .then on that Promise:
let addUser = (req, res) => {
let user;
let status = 200;
bcrypt.hash(password, salt_rounds, (err, hash) => {
user = new user({
password: hash,
});
const savePromise = new Promise((resolve, reject) => {
user.save(err => {
if (err) {
status = 400;
reject("No success");
} else {
resolve("success");
}
});
});
savePromise.then(message =>
res.status(status).json({ message })
).catch(message =>
res.status(status).json({ message })
);
});
};
Try this, put message key in double quotes
let addUser = (req, res) => {
let user;
let message = "";
let status = 200;
bcrypt.hash(password, salt_rounds, (err, hash) => {
user = new user({
...
password: hash,
});
user.save(err => {
if(err) {
message = "No success";
status = 400;
} else {
message = "success";
}
});
res.status(status).json({
"message": message,
});
});
};
I am new to NodeJS and JavaScript. I am badly stuck in a problem:
I want to generate QR image of 'some text' and after generating it, I want to query my MySQL database and insert the image to database.
Problem is that QRCode.toDataURL of SOLDAIR module goes in running state and query is called before the QR image is returned from the .toDataUrl function.
Hence it results in error.
I tried everything, promises, nested promises, counters, if statements etc., but I am unable to find a solution.
My code:
router.post('/generateTicket', (req,res) => {
const query1 = `SELECT * FROM booking ORDER BY bookingID DESC LIMIT 1`;
const query2 = `INSERT INTO ticket (ticket_image,BookingID) SET ?`;
let bookingID;
let count;
let ticket_data = {};
Promise.using(mysql.getSqlConn(), conn => {
conn.query(query1).then(resultOfQuery1 => {
bookingID = resultOfQuery1[0].BookingID;
count = resultOfQuery1[0].PeopleCount;
console.log("ID = " + bookingID + " people count = "+count);
promiseToCreateQRcode().then(function (URLfromResolve) {
console.log("the url is " + URLfromResolve );
}).catch(function (fromReject) {
console.log("Rejected "+ fromReject);
}); // catch of promise to create QR
}).catch(err => {
res.json({ status: 500, message: 'Error Occured in query 1 ' + err });
}); // catch of query 1
});
});
var opts = {
errorCorrectionLevel: 'H',
type: 'image/png',
rendererOpts: {
quality: 0.3
}
};
let promiseToCreateQRcode = function () {
let QRImage;
return new Promise(function (resolve,reject) {
QRCode.toDataURL('text', function (err, url) {
if (err) throw err
console.log("\n"+url+"\n");
QRImage = url;
});
if (QRImage)
resolve(QRImage);
else
reject("error occured in url");
});
};
As u can see, the program jumps to if statement and the QR image is not generated yet, hence it goes in "reject":
Try this,
let promiseToCreateQRcode = function () {
return new Promise(function (resolve,reject) {
QRCode.toDataURL('text', function (err, url) {
if (err){
reject(err); // or some message
} else {
resolve(url);
}
});
});
};
This way promise will be resolved only when toDataURL returns QR image.
Have a look at How do I convert an existing callback API to promises?. You need to call resolve or reject in the asynchronous callback!
function promiseToCreateQRcode() {
return new Promise(function(resolve,reject) {
QRCode.toDataURL('text', function (err, url) {
if (err) {
reject(err);
} else {
console.log("\n"+url+"\n");
resolve(url);
}
});
});
}
Using this extra QRImage variable like you did cannot work.