How do I use a callback in a nested function in Node? - javascript

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?

Related

Need help understanding parameters [duplicate]

I have trouble understanding how callbacks in JavaScript get their arguments. Or in other words: how to implement a higher-order function so its callback accepts for instance a standard err and data arguments.
Like in this article on asynchronous JavaScript in the example of a callback used in a usual way (and I know it's usual because I see exactly this pattern used in Node.js moongose (i.e. for creating data in db)):
function getData(options, callback) {
$.get("example.php", options, function(response) {
callback(null, JSON.parse(response));
}, function() {
callback(new Error("AJAX request failed!"));
});
}
// usage
getData({name: "John"}, function(err, data) {
if(err) {
console.log("Error! " + err.toString())
} else {
console.log(data);
}
});
how exactly the callback gets arguments err & data based on how getData() function is declared above?
Arguments are passed to a function when that function is called.
function foo(arg) {
console.log(arg);
}
foo("This is the value");
This is still true when it is a callback function.
function foo(arg) {
console.log(arg);
}
function bar(callback) {
callback("This is the value");
}
bar(foo);
And it is still true when the callback function is called by code written by someone else that exists in a library you aren't examining the source code of.

Callback mechanism in Javascript

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)
}
}

Javascript: pass parameters to callback function

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);

Trying to decode the word "callback" in this node.js code

I am new to node.js and came across this bit of code and am trying to understand what the word "callback" is doing. I mean I know what a callback is, but why are they actually using the word "callback" below and what is it doing. Really appreciate your help.
io.sockets.on('connection', function(socket) {
socket.on('nickname', function(data, callback) {
if (nicknames.indexOf(data) != -1) {
callback(false);
} else {
callback(true);
nicknames.push(data);
socket.nickname = data;
console.log('Nicknames are ' + nicknames);
}
});
});
It's a variable name.
It's defined in the function expression as an argument: function (data, callback) {.
The expectation is that the value passed to it will be a function (hence the function being called here: callback(false);).
For a simple example that doesn't depend on any library code you can't see:
function doSomething(callback) {
alert("doing something");
callback(1);
}
function myCallback(value) {
alert("myCallback called with the argument: " + value);
}
doSomething(myCallback);
But function (data, bob) is the callback function. Why include "callback" (or bob) within the callback. Does that make sense?
You have multiple callback functions.
One callback function is passed another function as an argument which it, in turn, calls.
Node.js uses asynchronous callback functions instead of blocking the caller and performing the operation synchronously. callback is simply the very common name given to the variable that holds the callback function. I usually name the variable done in my own code simply because it is shorter.
In Node.js, callback is the de-facto standard name for callback functions. You could easily call it bob, and it would have the same effect:
io.sockets.on('connection', function(socket) {
socket.on('nickname', function(data, bob) {
if (nicknames.indexOf(data) != -1) {
bob(false);
} else {
bob(true);
nicknames.push(data);
socket.nickname = data;
console.log('Nicknames are ' + nicknames);
}
});
});
As to what it's doing, think of it as an anonymous function that notifies the caller (like a parent function) that the called function is done. A simpler example would be:
Function A calls function B (which takes a long time to run). When B is done, it needs to tell A that it's done:
function a() {
b(someParameter, function(err, data) {
// function(err, data) is the anonymous function we pass as a parameter to b()
});
}
function b(someParemeter, callback) {
// do something that takes a while
// 'callback' is the variable name for the anonymous function that was passed
// We execute it using ():
callback(err, data);
}
Assuming that this is socket.io, that callback is used to respond to a client when the 'nickname' event is triggered.
From their documentation
Sending and getting data (acknowledgements)
Sometimes, you might want to get a callback when the client confirmed
the message reception.
To do this, simply pass a function as the last parameter of .send or
.emit. What’s more, when you use .emit, the acknowledgement is done by
you, which means you can also pass data along:
Server (app.js)
var io = require('socket.io')(80);
io.on('connection', function (socket) {
socket.on('ferret', function (name, fn) {
fn('woot');
});
});
Client (index.html)
<script>
var socket = io(); // TIP: io() with no args does auto-discovery
socket.on('connect', function () { // TIP: you can avoid listening on `connect` and listen on events directly too!
socket.emit('ferret', 'tobi', function (data) {
console.log(data); // data will be 'woot'
});
});
</script>

Function not returning results

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.

Categories

Resources