I am trying to pass a callback to a function, but keep getting the error,
Uncaught TypeError: callback is not a function.
loadContacts: function () {
var pageNumber = this.state.pageNumber,
pageSize = this.state.pageSize;
BasketService.getContacts(pageNumber, pageSize, function(contacts){
contacts = this.convertPropertyNames(contacts);
this.setState({
contacts: contacts
});
}.bind(this));
},
// trying to pass function callback here
listenerForRemoveContact: function(data){
BasketService.removePerson(data.id, this.loadContacts());
},
this.loadContacts() calls loadContacts and passes its return value to removePerson.
loadContacts doesn't have a return statement, so that value is undefined.
You are trying to use undefined as if it were a function.
If you want to pass loadContacts as the callback function, then don't call it: Remove the ().
Note that this will change the value of this inside the function, so you should also use bind() to maintain the context.
BasketService.removePerson(data.id, this.loadContacts);
^ you probably want to pass in the function object, not the result of calling the function
passing in
this.loadContacts()
will pass in the value which loadContacts returns (in this case it isn't returning anything)
Your code this.loadContacts() calls the function loadContacts and passes its return value to removePerson as argument.
loadContacts doesn't return anything, so the return value of that function is undefined.
If you want to pass loadContacts as the callback function, then don't invoke it just remove the invoking () from it.
Just pass like this
removePerson(data.id, this.loadContacts);
That's it.
Related
const getData = (cb) => {
setTimeout( () => {
cb({ data: ['there', 'is', 'stuff', 'here'] })
}, 100)
}
getData( data => {
console.log(data);
});
Here is the example of the javascript callback. Could some one let me know how this functions is executed into the javascript callback?
Here what is the function inside getData(cb) ? How it will be executed ? How the functions is passed as callback inside cb and return to the console.log
Regards.
The function inside getData is a callback being passed to setTimeout, which is one way to schedule a call to a function to happen in the future. In this case, it's asking for that callback to happen roughly 100ms later. getData returns before that happens.
The setTimeout callback is a closure¹ over the context where it's created, which means it has access to cb even after getData has returned. So when the browser's timer calls the callback, the callback can call cb. The call to cb uses an object literal to create an object to pass to cb.
In the call to getData, the author is passing a function as cb that logs the data it receives.
So:
getData is called, passing in a function that will log the argument it gets.
getData calls setTimeout to schedule a callback in about 100ms, passing in another function for the timer to call.
getData returns.
About 100ms later, the browser's timer subsystem triggers a call to the callback passed to setTimeout.
That callback creates an object and calls cb, passing the object to it.
That callback (the one passed to getData) logs the data object it receives.
¹ "closure" — see: SO, my anemic blog
In order to understand the code you can just simplify it by naming the anonymous functions. One example could be:
function logData(data) {
console.log(data);
}
const getData = (cb) => {
// `cb` is `logData` function when `getData` is called
function timeoutCallback() {
var data = { data: ['there', 'is', 'stuff', 'here'] };
cb(data);
}
setTimeout(timeoutCallback, 100)
}
getData(logData);
Does that make sense?
1- first global execution context created
2- get data function will be called then it will wait for 10 seconds inside the event loop then it will be come to execution context and printed to console.
I have a block of code like that
function doA (callback) {
//do something...
callback();
}
function doB (callback) {
//do something...
callback();
}
function doC () {
//do something...
}
i know it's a bad practice and have to avoid it, but i am trying to understand why when i called the functions as
doA(doB(doC)));
it throwed an error that "callback is not a function" ?
But when i tried:
doA(doC);
everything was ok.
edited: i have tried to use chrome dev tool to figure out how javascript callstack works here, and i found out that the call stack be like:
doC
doB
there isn't doA function, so why js avoids adding doA() to the callstack?
it throwed an error that "callback is not a function" ?
You call doA and pass the return value of doB(doC) as the first argument.
doB has no return statement, so it returns undefined.
doA tries to call the first argument (which has the value undefined) as a function, which it isn't, so it fails.
It isn't entirely clear what you are trying to achieve (since your example code has been abstracted so much), but you should probably investigate the Promises API which would let you do something like:
doA().then(doB).then(doC);
You are passing result of doB(doC) as the argument of doA but it is not a function:
doB(doC); // undefined
doA(undefined); // throws: callback is not a function
For callback you need to pass function and doB(doC) will execute it and will return undefined. And that undefined value will get passed to doA(undefined) and thats why you are getting -
callback is not a function
because doB it's not returning a function.
that expression means that the output of doB is passed as argument to doA, but since doB is not returning a function you get the error.
Here the function returns an anonymous function:
function respondWithResult(res, statusCode) {
statusCode = statusCode || 200;
return function(entity) {
if(entity) {
return res.status(statusCode).json(entity);
}
return null;
};
}
Why is it that we are returning an anonymous function here that returns a value? What advantages do we have and when to try something like this?
How and what is this anonymous function's argument entity is populated with? We passed res to respondWithResult and what exactly happens next that we got entity for an argument in the anonymous function? What value does this argument get populated with?
In case it gets populated with res only, what's wrong with directly doing this instead:
if(res){
//bla bla
}
return null
Edit: The function is called like this:
return Outlet.find().exec()
.then(respondWithResult(res))
.catch(handleError(res));
Now, res is what we pass to respondWithResult. Is that what the anonymous functions gets in the argument? If yes, what is the advantage?Why not use res directly?
Why is it that we are returning an anonymous function here that returns a value? What advantages do we have and when to try something like this?
This is generally done because it has access to the scope of the function it was declared within. i.e. the local variables statusCode and res. Without more context it isn't immediately obvious why that is useful here.
How and what is this anonymous function's argument entity is populated with?
It's a function argument. It gets populated with whatever gets passed to it when it is called (which isn't in the code you shared).
As you pointed out, the function is returned (not immediately executed). Some other code will call it later.
Now, res is what we pass to respondWithResult. Is that what the anonymous functions gets in the argument? If
No. The returned function is passed to then. When the promise resolves, the result is passed to it.
Please help me understand this:
I have an object self.domainSettings() which has a save method. The save returns the result which I want to use in callback function to populate success or error message. I am using following code:
self.domainSettings().save(function(data){
console.log('in here');
console.log(data);
console.log('outta here');
}());
function save(){
return 'success';
};
When I do console.log(data) is it guaranteed that the save has finished executing ? Also it says data is undefined because the return value of save is not getting passed to callback function I guess. How do I get that ?
You have to pass callback in save() in order to access the result from a callback.
function save(fn){
return fn('success');
};
I am using an ID3 reader script to retrieve data from audio files. The basic usage is:
ID3.loadTags(file,function()
{
var attr = ID3.getAllTags(file).attribute;
});
where the anonymous function is a callback function. This is just to provide context, however, I'm not at all sure the problem I'm having is specific to that particular script.
Typically, inside the callback function, you can extract the info you need and then use the DOM to set the innerHTML attribute of whatever element to equal the info you extracted.
Sometimes you're extracting a bunch of info and connecting all together in a long string though, and I'm trying to compartmentalize it a bit more so that my calling function will be a little cleaner. What I want to do is this:
function callingFunction()
{
var file = "whatever.mp3";
var info = getInfo(file);
}
function calledFunction(file)
{
var info = {data: 0};
ID3.loadTags(file, function(passedVar)
{
var dataobj = ID3.getAllTags(file);
passedVar.data = dataobj.title+etc+dataobj.album+....(it can get long);
}(info));
return info;
}
An object with an attribute is created because it's one of the only ways to simulate passing by reference in JS - pass the object into the callback function, assign the appropriate data to the attribute in the object, and then at the end of calledFunction, return the object to callingFunction.
It doesn't work though. Now, in that code above, if I said passedVar.data = "teststring" instead of assigning it data from dataobj, that would work, so the passing of the object into the callback function is working correctly. But if the object is assigned data from the data object that the ID3 function returns, it doesn't work. It comes back undefined, and furthermore, Chrome's JS debugger says that the object the ID3 function returns is null. This is further confirmed when I do this:
function calledFunction(file)
{
var info = {data: 0};
ID3.loadTags(file, function(passedVar)
{
alert(ID3.getAllTags(file).(any attribute));
}(info));
return info;
}
and no alert box comes up at all. But if remove the parameter being passed into the callback function in the code above, and leave everything else the same, that alert box comes up like it's supposed to.
So, to sum up, when I pass a parameter into the callback function, for some reason, another function of the object that's calling the callback function ceases to work correctly.
Is it possible that passing a parameter into the callback function is somehow conflicting with, or overriding, whatever the ID3.loadTags function is passing into the callback function, and that's why the getAllTags function is failing? Because for some reason when a parameter is passed into the callback function, the getAllTags function is no longer getting all of the information it needs to run properly? That's the only explanation I can think of.
If that's the case, is there a way to work around it? And if that's not what's going on, what is going on?
I have figured one solution, but I feel like it's hacky. I basically create a third function that gets called from the callback function(which itself receives no parameters), that takes as a parameter the object that the getAllTags method returns, extracts data from that object, and assigns it to global variables that other functions can access. So, this:
var globalVar;
function calledFunction(file)
{
//var info = {data: 0};
ID3.loadTags(file, function()
{
thirdFunction(ID3.getAllTags(file));
});
//return info;
}
function thirdFunction(dataobj)
{
globalVar = dataobj.title+etc;
}
But I don't really like that solution, I feel like it goes against the spirit of compartmentalization that I was after in the first place with this.
I'd appreciate any help.
The reason this doesn't work:
function calledFunction(file)
{
var info = {data: 0};
ID3.loadTags(file, function(passedVar)
{
var dataobj = ID3.getAllTags(file);
passedVar.data = dataobj.title+etc+dataobj.album+....(it can get long);
} (info));
// ^^^^^^ --- calls the function immediately
return info;
}
...is that you're calling your anonymous function and passing the result of that call (undefined) into ID3.loadTags. You're not passing a function into it anymore at all.
But the fundamental problem is that you're trying to use the data object before loadTags calls its callback and puts the data on the object.
I suggest that, since its output depends on an asynchronous operation, rather than relying on function return values, you change calledFunction to take a callback function. Here's what it should look like:
function callingFunction() {
getInfo('whatever.mp3', function(info) { // pass a callback function
// info.data is here now
});
}
function getInfo(file, cb) { // accept a callback function as the 2nd param
ID3.loadTags(file, function() {
var tags = ID3.getAllTags(file);
// once your async operation is done, call cb and pass back the return value
cb({
data: tags.title+etc+tags.album+....(it can get long);
});
});
}
This approach avoids problems you were trying to solve by using an object you could pass by reference, and it ensures you only move on once your asynchronous operation (ID3.getAllTags) is complete.