I'm trying to refactor some complexity into a function called getData but code that calls this function doesn't seem to be getting the results.
function getData(sql) {
pool.getConnection(function(err, connection) {
if (err) return;
connection.query(sql, function(err, rows) {
if (err) return;
if (rows.length > 0) {
console.log(rows); // This outputs result from table
return rows;
} else {
return [{"error":"Not found"}];
}
});
connection.end();
});
}
However, when it is called from a function like this, I get undefined returned, even though code inside the function works fine.
app.get('/1/employees/past', function(req, res, next) {
var rows = getData("select * from users");
res.json(rows);
})
Your return is returning from the inner function, which doesn't affect the outer function.
You'd need to capture it and return it, and seeing as it appears to work with callbacks, you'd need to pass an additional callback to getData().
Something like this...
function getData(sql, callback) {
// ...
connection.query(sql, function(err, rows) {
// ...
callback && callback(rows); // etc
});
// ...
}
If you wanted to be safer, ensure the callback implements [[Call]] with typeof (link to my own blog post).
Your getData function does not return anything - the return statements inside the code are all for the anonymous functions which you pass into connection.query and connection.query.
Your connection-related function are asynchronous - i.e. they return immediately after you call them without waiting for any results to be available. If you want to do something with the results which get returned you need to do it inside one of the anonymous functions, rather than trying to do it as soon as getData completes.
The getData function is not returning anything! The getConnection function inside the getData function is calling a function which calls a function which returns something; the getData function itself is not returning anything.
What's more, if this code executes asynchronously, all the returns will execute long after the getData function has returned.
You're either going the synchronous return route or the asynchronous callback route, you can't mix both styles.
Related
I'm receiving a "TypeError: callback is not a function" which leads me to believe I am misunderstanding how to use callbacks in a nested function.
Function:
function getAudioInfo(filePath, callback) {
ffprobe(filePath, { path: ffprobeStatic.path }, function (err, info) {
console.log("ffprobe output: " + JSON.stringify(info));
if (err) {
console.log("getAudioInfo error: " + err);
callback(err, null);
} else {
callback(null, info);
}
});
}
Call:
function checkAudioInfo(metadata_json, callback) {
var filePath = metadata_json['current_path'];
getAudioInfo(filePath, function(err, info) {
if (err) {
callback(err);
}
//operations on info
callback(null, metadata_json);
});//end getAudioInfo
}//end checkAudioInfo
Is this an improper use of callbacks?
Edit:
Error was found in passing to the function wrapping checkAudioInfo (another callback error). I will make edits and post the correct code shortly. All your questions helped me figure out the answer. Thanks!
Your first block of code accepts a callback. The second argument should be a function. This function will be called when the asynchronous code is done.
Your second block of code calls the function in the first. The second argument you are passing is a function. So far, so good.
Inside that function, you try to call callback. This fails because there is no variable with that name in scope.
At this point, it is very unclear what you are trying to do. The function you are passing is the callback. You are supposed to use it to do something useful with the data it is passed by the code from the first code block.
Now, you could get a reference to the callback function by using a named function expression:
getAudioInfo(filePath, function callback (err, info) {
if (err) {
callback(err);
}
//operations on info
callback(null, metadata_json);
});//end getAudioInfo
… but then you are just calling it recursively and infinitely, which is not useful.
re Edit:
You have now added a second variable called callback:
function checkAudioInfo(metadata_json, callback) {
This makes more sense.
If that callback is undefined, then that is because you aren't passing it a value when you call checkAudioInfo. You haven't included that code.
The function itself function(err, info) is the callback which is called inside of getAudioInfo!
What is metadata_json? Do you mean info?
I am trying to understand the callback mechanism in javascript(typescript). If I have a function which expects a callback as input argument, do I have to explicitly use a return statement to hook it up with the actually callback implementation form the calling code OR we can simply have use "callback" reference in the code being called and it automatically hooks up with callback code in the calling code
Code samples (typecript)
// callback code being hooked up using return statement
clear(collectionName: string, callback: any) {
this.getConnection((err, db) => {
if (!db)
return callback(err, null);
db.collection(collectionName).remove();
});
return callback();
}
// callback code being hooked up using reference to reserved callback keyword for automatic hook up with calling code
clear(collectionName: string, callback: any) {
this.getConnection((err, db) => {
if (!db)
return callback(err, null);
db.collection(collectionName).remove({}, callback);
});
}
You don't need to return, you can simply call it like
clear(collectionName: string, callback: any) {
this.getConnection((err, db) => {
if (!db)
callback(err, null);
db.collection(collectionName).remove();
});
return callback();
}
// callback code being hooked up using reference to reserved callback keyword for automatic hook up with calling code
clear(collectionName: string, callback: any) {
this.getConnection((err, db) => {
if (!db)
callback(err, null);
db.collection(collectionName).remove({}, callback);
});
}
No. Functions are first-class citizens in Javascript thus you can use them as a normal variables and pass them all around. You just need to call them (as normal functions) at proper moments. No return statement required. For example look at how Array.prototype.forEach works under the hood. It accepts the callback as a parameter that gets currently iterated element as a first argument and current index as a second argument:
Array.prototype.forEach = function(callback) {
for(i = 0; i < this.length; i++) {
if (callback) callback(this[i], i)
}
}
I want to call a function on the returned data from this database query, as in the snippet below.
function connectDB(query, data, callback) {
pg.connect(process.env.DATABASE_URL, function (err, client) {
if (err) {
console.log(err);
} else {
client
.query(query, data, function (err, result) {
callback(result.rows);
});
}
}
}
function foo(data) {
connectDB("SELECT * FROM mytable WHERE id=$1", someID, callbackfn(data));
}
I don't know how to write callbackfn so that I can use both data from the original function and rows from the db result.
function callbackfn(data) {
return function(rows) {
// Do something with rows and data
}
}
You don't accept any params with the callback function. How about:
function callback(rows) {
/* not sure what your intention was here? nested functions? */
return function () {
return function () {
// Do something with rows
}
}
}
And to be clear, can you post where you call the connectDB function? As callback is name of the variable after it is passed to connectDB.
Why are you defining callback function? Please elaborate on this. Also, try calling connectDB like this:
connectDB(query, data, function(rows) {
// Do something with rows
});
Read this answer on callbacks.
You have an incredible level of nested functions. Moreover, you are defining callback as parameter, but it won't take the callback function you defined, if you are not calling the base function passing again "callback" as argument.
If you want to pass always the same callback, it doesn't make sense that you provide it as argument, you can directly call "callback" inside your "connectDB" function. Moreover your callback returns a function, so it should be called again using again ().
Then your main callback function needs to accept rows as parameter from outside.
I kept your code using the callback parameter because I "hope" that the same name was just an example to explain that you want to provide every time a function in order to manipulate as you want the rows.
You code should look like this:
function connectDB(query, data, callback) {
pg.connect(process.env.DATABASE_URL, function (err, client) {
if (err) {
console.log(err);
} else {
client
.query(query, data, function (err, result) {
// this returns a function so it needs to be called again
callback(result.rows)();
});
}
}
}
// third inner function was useless
function callback(rows) {
return function () {
// Do something with rows
}
}
// the third parameter HAS TO BE callback, otherwise you will not pass the function you defined.
connectDB(query, data, callback);
I'm creating an application with SailsJS. I have a question about using callbacks within an Async waterfall and Async each.
I've got two functions inside an async waterfall function. The first callback returns the correct value. The second function has a nested callback. However, the value of the nested callback is stuck within the waterline find function, and never gets returned to the outer function.
Do you know how I could return the value to the outer function?
Thanks for your help.
myFunction: function (req,res) {
async.waterfall([
function(callback){
// native MongoDB search function that returns an Array of Objects
},
function(result, callback){
async.each(resultAll, function (location){
Model.find({location:'56d1653a34de610115d48aea'}).populate('location')
.exec(function(err, item, cb){
console.log (item) // returns the correct value, but the value cant be passed to the outer function
})
})
callback(null, result);
}], function (err, result) {
// result is 'd'
res.send (result)
}
)}
When you use async's function you should you should use you callback once you are done with operations you want to perform.
for example:
async.waterfall([
function(cb1){
model1.find().exec(function(err,rows1){
if(!err){
model2.find({}).exec(function(err,rows2){
var arr=[rows1,rows2];
cb1(null,arr);
});
}else
cb1(err);
})
},function(arr,cb2){
/**
* here in the array....we will find the array of rows1 and rows2 i.e.[rows1,rows2]
* */
model3.find().exec(err,rows3){
if(!err){
arr.push(rows3);
// this arr will now be [rows1,rows2,rows3]
}
else
cb2(err);
}
cb1(null,arr);
}],
function(err,finalArray){
if(err){
// error handling
}
else{
/**
* in finalArray we have [rows1,rows2] ,rows3 is not there in final array
* beacause cb2() was callbacked asynchronously with model3.find().exec() in second function
*/
}
});
so according to me your code should be like
async.waterfall([
function(callback){
// native MongoDB search function that returns an Array of Objects
},
function(result, callback){
async.each(resultAll, function (location){
Model.find({location:'56d1653a34de610115d48aea'}).populate('location')
.exec(function(err, item, cb){
console.log (item) // returns the correct value, but the value cant be passed to the outer function
callback(null, yourData);
/**
* yourData is the data whatever you want to recieve in final callbacks's second parameter
* i.e. callback(null,item) or callback(null,[result,item]) or callback(null,result)
*/
})
})
}], function (err, result) {
// result is 'd'
res.send (result)
}
);
Apply this and you can see things you want in your final callback.
I want to understand one thing about async module in node.js.
I have created a function that map an object from a form to a model object and return this object.
This object is a video with an array of tags.
My question is where can I return the video ? I know normally it is inside the async callback function but if I do that, the object returned is undefined.
Whereas If i return the video object at the end of the whole function, it works but it's not safe as I'm not sure, my async is finished...
By the way, I don't understand the callback function passed in argument to async.each and
called after video.products.push(tag); . What does this function do?
Regards
in my mapping.js :
exports.video = function(object) {
var video = new Video();
video.name = object.name;
video.products = [];
async.each(object.tags, function(tago, callback) {
tag = {
"name" : tago.name
}
video.products.push(tag);
callback();
} ,
function(err) {
if( err ) {
console.log('Error' + error);
throw err;
}
logger.debug("into async" + video);
}
);
logger.debug("end function " );
**//return video;**
}
in my video.js :
var video = mapping.video(object);
logger.debug(video); // return undefined
The simple answer is that you can't - at least not via easy or obvious approach. As its name suggests, async is a library for queuing up asynchronous function calls into the event loop. So your exports.video function simply kicks off a bunch of asynchronous functions, which execute one after the other on an unpredictable time-frame, and then returns immediately. No matter where you try to return your video object within the scope of your function calls which are instantiated by async, the exports.video function will already have returned.
In this case it doesn't really seem like you need asynchronous function calls for what you're doing. I'd suggest that you replace your use of async with something like Underscore's each method, which executes synchronously, instead.
http://documentcloud.github.io/underscore/#each
You'd need to define a callback for your exports.video function e.g..
exports.video = function(object, callback) {
// video code (snip)...
async.each(object.tags,
function eachTag(tag, done) {
// code run for each tag object (snip)...
done();
},
function finished(err) {
// code run at the end (snip)...
callback(thingThatsReturned);
});
};
...and call it like this:
var videoUtils = require('videoUtils');
var tags = getTags();
videoUtils.video({ tags: tags }, function(thingThatsReturned) {
// do something with 'thingThatsReturned'
});
By the way, I don't understand the callback function passed in
argument to async.each and called after video.products.push(tag); .
What does this function do?
The async.each function will call the 'eachTag' function above (2nd argument) for each item in your array. But because it's done asynchronously, and you might do something else async in the function (hit a database/api etc.), it needs to know when that function for that particular array item has finished. Calling done() tells async.each that the function has finished processing. Once all the functions are finished processing (they've all called done()), async.each will run the 'finished' function above (3rd argument).
This is pretty standard async stuff for Node.js, but it can be tricky to get ones head around it at first. Hang in there :-)
Edit: It looks like your code isn't doing anything asynchronous. If it was, then the above code would be the way to do it, otherwise the following code would work better:
exports.video = function(object) {
// video code (snip)...
if (Array.isArray(object.tags)) {
object.tags.forEach(function eachTag(tag) {
// code run for each tag object (snip)...
});
}
return thingThatsReturned;
};
...and call it...
var videoUtils = require('videoUtils');
var tags = getTags();
var thingThatsReturned = videoUtils.video({ tags: tags });