Understanding callback function parameters - javascript

I've been trying to understand callback functions and I'm unsure where the data variable/object is actually coming from in this example:
$.get( "ajax/test.html", function( data ) {
console.log(data);
});
I think of this function being defined as something like this:
$.get = function(url, callback) {
// send request to url
callback(data); // execute callback function... but where is data coming from/being defined?
};

I've been trying to understand callback functions and I'm unsure where
the data variable/object is actually coming from in this example:
you invoked jquery function $.get() and gave a handle to your anonymous function as a parameter. jquery did all the work on invoking ajax methods, getting the response (data) and finally invoke your anonymous function (which you passed on to it as parameter). data variable is then passed on to this anonymous function by the same jquery function.

Related

Callback function syntax - why is this not allowed?

function callbackFn(res){console.log(res)}
I can write
$.get("./a", function(response) {callbackFn(response)});
Why can't I write
$.get("./a", callbackFn(response));
Just pass the function reference to $.get()
$.get("./a", callbackFn)
Demo
function handleResponse(data) {
console.log('response data:\n', data);
}
$.getJSON('https://jsonplaceholder.typicode.com/todos/1', handleResponse)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Functions are values in javascript, special objects is you will.
When you define a function like
function callbackFn(res) {
console.log(res)
}
callbackFn references the function itself and callbackFn() executes or call the function and you get the value that this function returns.
The method you are showing is expecting an string as the first parameter and a function as the second.
So if you do:
$.get("./a", callbackFn(response));
You are passing to $.get the return value of calling the function with the argument response (ie. callbackFn(response)).
To make it clearer, this is how a method like this is defined (this is an example, not the actual implementation)
function get(path, callback) {
fetch(path).then(function (response) {
callback(response)
})
}
As you can see, inside get, it's calling the function that is expected as a second parameter with the argument response (your callbackFn).
The second version calls callbackFn() immediately, and uses its return value as the second argument to $.get(). It's equivalent to
var temp = callbackFn(response):
$.get("./a", temp);
You need to wrap it in an anonymous function so that it won't be called immediately, but instead when $.get completes the AJAX request.

Passing callback functions as arguments in vanilla JS ajax

I am working on an ajax function to retrieve info from the database. I set up the API and the ajax function does retrieve proper values, but the callback function I passed as an argument won't work on onreadystatechange.
Simplified Code below
function serializeArgs(args) {
//Serialize Arguments
}
function callback(a) { //The function to be called as callback
//Process the response and add contents to the page
}
function getListData(callback) {
var ajaxOptions = {
action: "get_data",
}
var request = new XMLHttpRequest();
request.open("POST", apiurl, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8');
request.setRequestHeader("Accept-language", "en-US");
request.onreadystatechange = function(event) {
if (this.readyState == 4 && this.status == 200) {
callback(this.response);
}
};
request.send(serializeArgs(ajaxOptions));
}
When I run the function, I get the error "TypeError: callback is not a function"
I have been struggling with this all day, but since I am not that experienced with ajax, I could not figure out why this is happening, and how to solve it. I have a hunch that it has something to do with the asynchronous nature of the ajax, but I'm not sure how I can work around this.
Short reference for this error:
You usually get this error when the following happens:
When a function call is made on a property of that simply isn’t a function.
When a function call is made on an object type that doesn’t contain that function or method.
When a function call is made on a built-in method that expects a callback function argument to be provided, but no such function exists.
I noticed the following in your ajax function:
Your parameter is named callback, just like your function callback. What your ajax function is trying to do is use the parameter callback as a function (not sure if you pass the function callback in as a parameter, if you do, then it's alright, but since I cannot see where you are calling getListData function, I can only guess you are calling it without passing the function callback as an argument).
//Your function callback is trying to access this parameter.
//So unless your actual function callback is being passed in as an argument,
//it's most likely trying to access your parameter even though it is NOT a function or it isn't even receiving a function as parameter
function getListData(callback)
function callback(a)
However if you are trying to simply access it as a function (and not as a callback) i'd recommend changing the parameter name or function name callback.
So to show an example:
First way of doing what you are trying to achieve (callback way).
Call your function this way:
getListData(callback)
Or do the following:
function getListData(changedParamName) {
//this way you can now call your callback function and pass this.response to it
}
That should do the trick.
Where do you call the function getListData?
My guess is, that you call it like getListData() without passing the callback function.
if you call it like getListData(callback) it should work. Hard to say what happens without the full code example.
just for testing you also can change the line
function getListData(callback) {
to
function getListData() {
just to see if it works.
In the second szenario, you don't pass the callback, so when you call the callback function, Javascript will look for it in the parent scope.

Geolocation function parameters behavior

I'm using the google maps api and I've noticed a programmatic behavior that I'm not familiar with in JavaScript:
function success(pos) {
// ...do something with pos.
}
navigator.geolocation.getCurrentPosition(success);
In the example above it appears as though the success function is passed a 'pos' argument from thin air and the success function isn't invoked inside the getCurrentPosition argument via parentheses. I would expect to see something like this:
function success(pos) {
//...do something with pos.
}
var pos = //...something;
navigator.geolocation.getCurrentPosition(success(pos));
I just don't understand what is going on here. Where does the argument come from and why isn't the function even invoked with parentheses?
This is a feature you will see often in Javascript. It is commonly called a callback. The lack of parentheses is because Javascript allows you to treat a function like a variable, often referred to as 'first-class functions'. You are passing the success function to the getCurrentPosition method, you are not actually calling the success method.
When you call navigator.geolocation.getCurrentPosition(success);, you are saying to the getCurrentPosition function that when it has found the position, you would like it to call the function you have provided and pass it the position it got.
The getCurrentPosition method will be doing something like the following:
function getCurrentPosition(successCallback) {
var position = loadFromSomewhereThatMayTakeAWhile();
successCallback(position);
}
getCurrentPosition may take many seconds or even minutes to get the current location. You do not want the browser to stop responding while this is happening. Callbacks allow you to say "when this operation has finished, call this other method to do something with the result". The browser can then carry on with other things and only execute your callback when the operation is complete.
The jQuery ajax function uses this callback style.
var whenSuccessful = function(data, status, xhr){
console.log('The data was loaded successfully.')
};
var whenFailed = function(xhr, status, error){
console.log('The request failed!')
};
$.ajax({
url: "http://myserver.com/some_data.json",
error: whenFailed, // do this if the request fails for any reason
success: whenSuccessful // do this if the data was loaded successfully
})

return object from function is undefined from $.post in jquery

I've a jquery post function that returns a data object from a php code block.
$.post("get_chat_history.php", {
item_id : item_id,
participant_1 : participant_1,
participant_2 : participant_2
}, function(data) {
alert(data);
return data;
});
this is called from the following function in another javascript file
var data = getChatHistory(current_member_id,item_global["user"] ["member_id"],item_global["id"]);
alert(data);
now inside the $.post the alert(data) throws out the correct values in json format, but when I test the same value returned to the calling function I get undefined.
Is there something I'm missing as I want to keep this function generic and callable from elsewhere??
Regards,
Sapatos
That's because this function runs asyncronim and returns data to anonymous function function(data) {}. Use callbacks.
Here is example:
function getFoo(callback){
$.get('somepage.html', function(data){
callback(data)
})
}
getFoo(function (data){
// do something with data
})​
The problem you are facing is that jQuery.post is asynchronous. When getChatHistory is being called it has not yet received a reply from the server so it is undefined.
For this to work I would implement getChatHistory as a function that takes the data you need to pass to the server, and a function to perform when the 'success' part is triggered.
For more on callbacks.

Why is return not working in getJSON and why cant I write into variable from getJSON?

I have a function which uses getJSON but its not working like I expected.
function balbla(name, param) {
$.getJSON("/blabla.json?name=" + name + "&param=" + param, function(data) {
return data.bla;
});
}
When I use alert(data.bla) in the getJSON method it works but when I try return data.bla it doesnt. Also when I create a variable and try to write the value of data.bla to it it simply doesnt work!
// I tried this:
function getRouteData(name, param) {
return $.getJSON('/routes_js.json', {route:name, opt: param});
}
function getRoute(name, param) {
getRouteData(name, param).done(function(data) {
return data.route;
});
}
But when I call getRoute("bla", "blub") it still returns undefined.
AJAX is asynchronous. You cannot easily return a value in such a function that depends on the result of the AJAX call. Change your function to accept a callback:
function balbla(name, param, cb) {
$.getJSON('/blabla.json', {name:name, param: param}, function(data) {
cb(data.bla);
});
}
And use it like this:
balbla('foo', 'bar', function(bla) {
// do stuff
});
An even cleaner way would be returning the jqXHR object:
function balbla(name, param) {
return $.getJSON('/blabla.json', {name:name, param: param});
}
When calling it, use the deferred/promise interface of the jqXHR object to attach a success callback:
balbla('foo', 'bar').done(function(data) {
alert(data.bla);
});
Note that using $.ajax() in synchronous mode is not an option you should consider at all. It may hang the browser's UI (or at least the active tab) until the request finished. Besides that, asynchronous callbacks are the way everyone does it.
If you do not like using callback functions, you could use a preprocessor such as tamejs to generate the asynchronous functions automatically.
The function with your return statement:
function(data) {
return data.bla;
}
… is not being called by your code (it is being called deep inside jQuery), so you have no way to put an assignment of the left hand side of the function call.
It is also being called as part of an asynchronous function, so the balbla function will have finished running and returned before it the anonymous one is ever called.
If you want to do something with the response data, do it inside the anonymous callback function.
getJSON is asynchronous, not synchronous. You need to use a callback so your logic needs to be done in two steps. Calling step and the processing step.

Categories