Check my updated answer below the other answers. The question turned out to be quite simple, I just didn't understand how async worked or should be handled at the time of posting it
I have the following code:
function qcallb(err,result){
console.log("result.insertID:"+result.insertId);
return result.insertId;
}
var createRecord= function (tableName,record){
try{
queryStatment="INSERT INTO " + tableName + " SET ?";
var result='';
var query = connection.query(queryStatment, record, qcallb,false);
}
catch(err){
return 0;
}
return iid;
}
I want to return the variable result.insertId from the callback function, to the function that calls create record, but I have not found a way to do this.
I tried to set a global variable in the callback function, but when I try to access it, its value is still unchanged.
Is there a way for me to either access the value directly in the callback function, or to have callback function notify me when it's called then return the value?
EDIT:
After testing every proposed solution here, and those that I found by searching elsewhere, the only thing that worked for me (without using external modules to make a piece of code run in 'sync' rather than 'async'), was to implement the logic I wanted inside the callback itself, which is what I wanted to avoid in the first place, but I couldn't work around it no matter what I did.
2 years later:
After getting much more experience with node.js and async code, I see how naive this question was, although it was beyond me at the time, which is also obvious in my using a try/catch block around an async call which is useless with async code, where handling errors is done by checking for err in the callback and acting upon it if it exists.
Since it seems to have quite a number of views, this seems to be a recurring issue for those newly introduced to async development.
This can't be done in the sense that was asked in the question, for an operation to occur after an async operation and use a value that is a result of the async operation, it has to be called from the callback of the async operation with that value.
To resolve the issue, the code can be modified to:
function doSomethingWithResult(result) {
// query is done, and this would only be called if no error occurred
console.log('Result is: ', result)
// do whatever you want
}
function queryCallback(err,result) {
if (err) {
throw err
}
doSomethingWithResult(result)
}
function createRecord(tableName, record) {
queryStatment='INSERT INTO `' + tableName + '` SET ?'
connection.query(queryStatment, record, queryCallback)
}
---
Old Answer: After testing every proposed solution here, and those that I found by searching elsewhere, the only thing that worked for me (without using external modules to make a piece of code run in 'sync' rather than 'async'), was to implement the logic I wanted inside the callback itself, which is what I wanted to avoid in the first place, but I couldn't work around it no matter what I did.
Yes, 'notify me' is the way to go:
var createRecord= function (tableName,record, cb){
var query = "INSERT INTO " + connection.escape(tableName) + " SET ?";
connection.query(query, record, function(err, res) {
if (err) return cb(err);
cb(null, res.insertId); // this is "notify me" part
});
}
// now use it
createRecord('blah', { foo: "bar" }, function(err, id) {
console.log(id);
});
Also, try/catch won't help much here as callback function is not executed down stack frame but called outside from event loop. You need to use domains/zones or some similar sort of async error handling
i think there is a way with waiting for the response with an endless loop, maybe you can also use the context to assign the variable like so :
var sleep = require('sleep');
var createRecord= function (tableName,record){
try{
queryStatment="INSERT INTO " + tableName + " SET ?";
var insertId=0;
var query = connection.query(queryStatment, record, function(err,result){
console.log("result.insertID:"+result.insertId);
insertId = result.insertId;
},false);
}
catch(err){
return 0;
}
while(insertId==0){
sleep.sleep(0.1); # sleep for 0.1 second
}
return insertId;
}
i haven't tested this code on my machine, please test it and let me know if there is any error.
Related
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'm trying to send back results data from my API call in Node. I have an HTML form with a search bar set up that takes the search term and fires off a search with that term.
Right now the data gets sent back and is empty on the first click, but when I click again, the data from the previous call is sent back to my HTML page, so I know there's something going on in regards to callbacks. I could use a setTimeout on the res.json() but that seems a little...juvenile.
I am pretty new to Node and I know the solution is rather simple...but I can't quite seem to figure it out.
Promises, callbacks, async. Maybe I'm just a little confused on where they go...
var result;
var Questrade = require("questrade");
var qt = new Questrade("env.KEY")
qt.account = "env.ACCOUNT";
qt.on("ready", function(err) {
if (err) {
console.log(err);
}
});
function searchQt() {
qt.search(searchTerm, function(err, symbols) {
if (err) {
console.log(err);
}
result = symbols;
});
}
app.get("/search", function(req, res) {
searchTerm = req.query.symbol;
searchQt();
res.json(result);
});
I'm expecting to receive my data back on time.
Easiest and most incremental solution would be to move res.json(result) to the callback where the value of result is received.
function searchQt(res) { // <-- note added argument
qt.search(searchTerm, function(err, symbols) {
if (err) {
console.log(err);
}
result = symbols;
res.json(result); // here it is!
});
}
app.get("/search", function(req, res) {
searchTerm = req.query.symbol;
searchQt(res); <-- note added argument
// res.json(result); <-- commented out and moved above
});
You could also make things work with promises or async/await, but since you're already using callbacks, this is the most incremental way to get to working code.
While you're in there, you should remove result from the outer scope. You don't need or want that value preserved between requests. So just res.json(symbols); and get rid of the results variable entirely.
And passing res as an argument like that above is a bit of a code smell. Let's move the call to qt.search() directly into the callback for app.get() to clean things up a tiny bit. This eliminates the searchQt() function entirely:
app.get("/search", function(req, res) {
searchTerm = req.query.symbol;
qt.search(searchTerm, function(err, symbols) {
if (err) {
// handle error here somehow. maybe something like this?
console.log(`An error occurred: ${err}`);
res.status(500).end('An error occurred');
return;
}
res.json(symbols);
});
});
There are still some other improvements possible here. (I'm not sure if the ready event needs to fire before a search is tried, for example. So there might be a race condition there.) Promises or async/await might make this more readable. (People seem to like those better than deeply-nested callbacks. I personally don't mind the nesting, but I get it.) But that hopefully gets you going in the right direction. (And hopefully I didn't add any bugs that weren't there before!)
I am trying to implement a function to check if a doc exists in my FireStore database, given an id. The problem is my fire_PatronExists function always return undefined.
const patronsRef = db.collection("patrons");
alert(fire_PatronExists(user.uid));
function fire_PatronExists(id) {
patronsRef.doc(id).get().then(function(doc) {
// return doc.exists();
if (doc){return true}else {return false}
}).catch(function(error) {
console.log("Error getting document:", error);
});
}
The fact that your function returns undefined is totally normal: get() is an asynchronous method, so the return you put inside the then will not be executed inside fire_PatronExists; it will be executed a bit later. There is a great SO article that explains the difference between synchronous and asynchronous execution.
There are different solutions, depending on the version of JavaScript you are using. One that will work for sure is passing a callback function to fire_PatronExists and pass the result to that function.
This would look like that (not tested):
const patronsRef = db.collection("patrons");
fire_PatronExists(user.uid, function(exists) {
alert(exists);
});
// Remember though, if you put code here, it will be executed in parallel
// with the code you put inside your callback.
function fire_PatronExists(id, callback) {
patronsRef.doc(id).get().then(function(doc) {
}).catch(function(error) {
console.log("Error getting document:", error);
});
}
Using callbacks can get really messy though. If you are using a recent version of JavaScript, you might want to read about the async and await keywords, they can improve your code readability a lot.
Commonly, an async function in js returns a promise wrapping either the resolved value or error message. If promise style do not apply, a callback can be passed as a parameter to that async function, in which the result of the async function is accessible.
Just wonder if it is meaningful for such a callback to have a return statement? If so, who can receive the returned value and is there any useful use case?
Here's a piece of code to illustrate the concept you are trying to understand.
var callback = function(err, result){
if(err){
console.log(err);
return err;
}
callAnotherFunction(result);
};
function getRandom(cb){
//do something
var result = Math.random();
if(result > 0.5){
return cb(result);
}
return cb(null, result);
}
getRandom(callback);
The function getRandom() will return an error if the random number is less than 0.5, a value otherwise. The callback then handles the response differently depending on the values passed to the callback function. As you can see, the return statement inside the callback makes a big difference. By the way, the above example demonstrates a standard error-first design pattern in NodeJS.
Theoretically, any async function should return something like a handler, which you can use to track progress, or cancel the on-going async actions, example:
var timer = setTimeout(..)
clearTimeout(timer)
Because the return value is the only chance that you can get this handler in a sync manner, but it seems people don't quite care about this and invent all kinds of stuff to solve async cancellation problem, please read more about this on my note on action-js.
In a perfect world, we should get a handler for every async function:
handler = fs.readFile('...', function(err, data){...});
xhr = ajax('...', function(err, data){...});
...
Whats the proper way to wrap a mongo query/insert in a function to make it reusable? I have an update operation that may take place in various places and want to only write it once and reuse it. I'm using MongoJS to interface w/ the MongoDb API.
When I take something like the following:
mongo.myt.update(
{'_id': req._id},
{
$addToSet: {
"aggregate.clientIds": req.myt.clientIds
},
$inc: {"aggregate.seenCount": 1},
$set: {
"headers": req.myt.headers,
"ip": req.myt.ip
},
$setOnInsert: {
'_id': req.myt._id,
'derived': req.myt.derived
}
},
{upsert: true},
function (err, savedId) {
if (err || !savedId) console.log("failed to save :" + req.myt + " because of " + err);
else console.log("successfully saved :" + req.myt);
});
And wrap it with a simple function like:
function mongoInsert(req) {
//same query as above
}
Then call it using:
mongoInsert(req);
I don't see any impact to speed when profiling. Should I be adding a callback to the wrapper function, is that needed? I was expecting it would have some performance impact and need to be done differently.
So a few questions.
Does the approach above calling mongoInsert() get called synchronously and block until the async mongo update is done?
If it does become sync, I would expect a performance impact which I didnt see. So is the approach I took ok to use?
And if not what would be the correct way to do this?
mongoInsert() is still asynchronous because it's calling an asynchronous function (mongo.myt.update()). Even if you don't add a callback function, it won't magically become synchronous.
The way you wrote it now is "fire-and-forget": somewhere in your code you call mongoInsert(), your code will continue to run while the update is taking place, and since you don't pass a callback the calling code cannot get informed about the result of the update (right now, you're just logging the result to console).
It's a design decision whether or not this is acceptable.
You could make the callback optional for situations where you do want to get informed about the update result:
function mongoInsert(req, callback) {
callback = callback || function() {}; // dummy callback when none is provided
mongo.myt.update(..., function(err, savedId) {
...log status here...
callback(err, savedId);
});
}
I am trying to pull a variable's value from a callback function.
What am I doing wrong here?
var storyList = [];
var storyTemp ={};
// get list of all stories
db.getAllStoriesSet(function(err, reply) {
if (err) throw err;
else {
storyList = reply;
console.log("storylist inner: " + storyList);
};
});
console.log("storylist outer: " + storyList);
in the above code, I am expecting the inner and outer storylist values to be same.
however the outer storyList value still comes as a null list.
EDIT: to add to the question.
I have initialized a variable storyList outside the async function. i am then taking the reply from the async function and putting it in the variable storyList. I was hoping to cheat my way out of the async pit of slow and brutal death that I have apparently dug for myself.
shouldnt it have worked?
If getAllStoriesSet is asynchronous, then the line following its call is called before the callback is executed. So storyList is just like it was before the call.
That's the reason why you provide a callback : you must put inside the callback the code which needs the value of reply.