I've followed this explanation here, but am still unsure how callbacks work.
I do my call here:
scene.foo(scene.myCallBack("mymap"));
And my callback stuff here:
1) scene.foo calls foo and passes in CallBack function with "mymap" JSON data
2) foo's $.ajax defines its success as the passed in CallBack. Once the data is processed, success calls the callback, myCallBack()
3) myCallBack attempts to getJSON from the file name and console.log it as a string with JSON.stringfy
Am I not understanding this correctly?
foo : function (callback) {
$.ajax({
success: callback //once AJAX request is successfull, $.ajax will call callback (myCallBack) and pass response back to callback
});
},
myCallBack : function (name) {
$.getJSON("C:/Users/danniu/Desktop/JavaScript/tilemap/maps/" + name + ".json", function (data) {
var myJSONText = JSON.stringify(data);
console.log("json: " + this.myJSONText);
});
},
You're close to the solution.
scene.foo(scene.myCallBack("mymap")); first exectue scene.myCallBack("mymap") and then the result is passed to scene.foo(...)
It's similar to write:
var result = scene.myCallBack("mymap");
secene.foo(result);
This is pretty weird in this case, because scene.myCallBack("mymap"); doesn't return anything interesting to scene.foo
Note that $.getJSON(...) already does an Ajax request for you.
As soon as you stick parentheses on, it stops being a callback. scene.myCallBack can act as a callback; scene.myCallBack("mymap") is just undefined (the return value of your function, as it does not have an explicit return statement and thus implicitly returns undefined).
If you want to have he $.ajax do myCallBack on success AND have custom arguments with it, you need to wrap it:
scene.foo(function() { scene.myCallBack("mymap"); });
Or equivalently,
fooCallback = function() { scene.myCallBack("mymap"; };
scene.foo(fooCallback);
EDIT to clarify some concepts:
And can you explain why putting parentheses on it makes it not a callback?
Putting parentheses on a function executes a function, giving a value back. A callback must be a function.
For example, let's say your Mum wants you to eat an apple when you get home. She could leave you a note, "Growler, when you get home, eat an apple!":
var eatApple = function() {
growler.eat('apple');
}
growler.on('getHome', eatApple);
is one way to write such a thing. However, if you write
growler.on('getHome', eatApple());
it's like your Mum feeding you an apple, then writing a note "Growler, when you get home, __" and placing the apple core on the blank. I don't know about you, but I'd be rather surprised by such a note; and I daresay your JavaScript interpreter is likewise surprised as well.
A callback is a function to be done at a later time. If you execute it (with parentheses), you are only left with the function's results; and thus the function is not a callback, since your event will try to call back the result (the apple core), and not the function (process of eating an apple).
(An advanced topic is a function that returns a function; in this case, the result can be the callback, such as, growler.on('getHome', whatShouldIDoNow()). whatShouldIDoNow is still not a callback; the function that it would return would be.)
If $.getJSON is already an AJAX request, how can I get the callback from that?
I do not understand the question. You provide $.getJSON with callbacks at the time you invoke it; those functions will be called back at the appropriate time, if such happens.
Related
I have three functions that all work with data from a global object. This global object gets filled with data from a local array in one function and with data from an ajax request with the second function. The third function relies on the data in the object, so the ajax request must have been completed.
I believe I am misunderstanding callbacks. Here's what I do:
var currentCharacter = {}
// this function gets the local data and then calls the second function
function loadData(getMarvelData) {
// do things to fill currentCharacter
getMarvelData(); // this is the callback to the next function (no ?)
}
// this function performs the ajax request, then calls the third function
function getMarvelData(getGoogleMap) {
// do ajax request and add stuff to currentCharacter
getGoogleMap(); // this is the callback to the final function (no ?)
}
function getGoogleMap() {
// do Google Map related stuff with data from currentCharacter
}
I thought setting a function as an argument of another function and then executing it would make the function dependent on the other before it continues. Clearly I still misunderstand callbacks after trying to make it work for a week now. As it is, the getMarvelData function doesn't even get called because I never see the alert popup and the currentCharacter object only has data from the loadData function.
Could somebody show the correct approach for my code, or if my approach of making these three functions is even the right one for this scenario.
The full repository is available at: https://github.com/ChaMbuna/Marvel-Map
V0.9 was actually working but the ajax call was set to run synchronous (it still is btw) Since then I've been overhauling my code to make it work asynchronously and to remove all jQuery (this is a Udacity project and removing jQuery was suggested by an instructor).
Appreciate the help
I have not enough reputation to put a comment, but a wild guess, you should remove the argument in loadData&getMarvelData or actually pass a function in calls to those function.
You have to pass the parameters correctly.
Try this:
var currentCharacter = {}
loadData(getMarvelData, getGoogleMap);
function loadData(f1, f2) {
// do sth.
f1(f2);
}
function getMarvelData(f2) {
// do sth.
f2();
}
function getGoogleMap() {
// do sth.
}
I havn't tested it, but it should work.
I've started recently to learn about javascript, and I saw a lot of callback functions.
What are those functions, why they are used and what for?
I will be happy to get really basic definition, because I wanna understand it because I realised that it is really important in js.
thanks :)
A callback function is a function you pass as an argument to another function.
The callback function will be called by the function you pass it to (or one further down the chain).
This is typically done when the function is doing something asynchronous, so you can't use a return value.
The main examples are for events:
// call someFunction when the document is loaded
addEventListener('load', someFunction);
or time related calls:
// call someFunction after 30 seconds have elapsed
setTimeout(someFunction, 30000);
As the name suggests, callback functions are anonymous or named functions that are passed as arguments to another function, or an AJAX call etc. and will be executed after a certain action is completed by the javascript engine.
For eg. You can pass a callback function to be executed once an AJAX call has returned with data. Ill use jQuery for simplicity :
$.ajax( {
url: "/my-api-path/",
data: myParams
}).done(myCallback);
Here, myCallback is a function that will be executed once the AJAX call completes. The callback function in this case will be called with the response object returned by the AJAX call. Notice how this callback has been passed as an argument to the .done method provided by jQuery's AJAX API.
In another example,
setTimeout(
function() {
alert("Im inside a callback function!");
}, 2000 );
Here the function that contains the alert is the first of the two arguments passed to the setTimeout method in javascript. The second being the amount of milliseconds after which this function should be executed. Since this function does not have a name it is called an anonymous function.
The same code could be re-written as :
var myCallback = function(){
alert("Im inside a callback");
};
setTimeout(myCallback, 2000);
Callbacks are executed immediately when the action completes. So after the engine encounters the setTimeout statement it will store the myCallback function in a reference and then continue execution after the setTimeout statement. Once 2 seconds elapse, it will realise its time to execute the callback so execution will jump to the callback. Then the alert will execute, the callback function will terminate and execution will continue back from where it was when 2 seconds elapsed and the engine jumped to the callback.
Hope this explains how callbacks work.
As we know we can pass different type of variable, object as function's parameter . In javascript if a function is passed as parameter then it is called Callback funbction.
The callback function is called on some event/condition till then the program can execute other code. The callback function would executed only when the particular event is occurred or particular condition is satisfied.
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.
See the following line of code:
WinJS.xhr({ url: "http://someurl.com" }).then(
function fulfilled(result)
{
if (result.status === 200)
{
resDiv.style.backgroundColor = "lightGreen";
resDiv.innerText = "Success";
}
});
As far as I understand, when WinJS.xhr has completed whatever it does then execute the anonymous function 'fulfilled' with argument 'result'
Coming from Java/C++ background, I'm extremely confused with how this code works - how is 'result' being passed to this function? Where does it say anything about what 'result' is? How can I know what type of object 'result' is and how it has a 'status' member?
I'm going to break my answer into two parts: The first concerns the actual execution model of Javascript, and the second which concerns the high-level expression as written.
The Javascript Execution Model
WinJS evaluates to an object.
That object has a prototype which contains an xhr member which WinJS.xhr evaluates to. That member is a function, which we will refer to as A below so that we can keep clear what exactly is going on.
Before we get to that, { url: "http://someurl.com" } returns an object which we will refer to as B.
That object B has a property called url.
A(B) calls a function A with a value B as an argument. It returns an object that we will refer to as C.
That object C has a prototype which contains a member named then. C.then happens to evaluate to a function. That function we will refer to as D.
function fulfilled(result) {...} returns a function that we will refer to as E. It can also be referred to as fulfilled but that fact is not used in this program fragment.
D(E) calls a function D with a value E as an argument. Nothing is done with the return value.
The high-level view
There are three functions here; one is a callback (called fulfilled), and the other two may be called "methods"- one xhr of the WinJS global object, and then of a promise object.
WinJS.xhr({ url: "http://someurl.com" }) creates and returns that promise object. You can convince yourself of this by consulting the documentation.
The promise object has a method called then which registers what you can think of as an event handler for when the promise is done. The value result - used in that callback registered in then comes from whatever is making that promise done by in fact calling the method done on that promise. You don't see the code that does that because it's someplace in the implementation of WinJS.xhr.
What WinJS.xhr is doing is performing a network request. When that network request is done it will signal the result of that network request (which according to the documentation is an XMLHttpRequest object) through the promise by calling the done() method on that promise. That in-turn calls the callback we registered with the then() method.
The documentation for the WinJS functions is still not great, IMO. You can look at the documentation for WinJS.xhr at http://msdn.microsoft.com/en-us/library/windows/apps/br229787.aspx, and that will give you some information on that - it says that the xhr function "wraps ... XMLHttpRequest object in a promise". Personally I've found it easier to look at the examples / quickstarts than at the reference documentations.
What you have passed to the fulfilled function (or the first function there) isn't the "result" of the operation, but the XMLHttpRequest object itself. On that you can get its properties to see the result - take a look at http://msdn.microsoft.com/en-us/library/windows/apps/ms535874.aspx for its reference.
The xhr method returns a Promise object, which has the then method that takes the onComplete, onError and onProcress callback functions.
This code only uses the onComplete callback. The callback is called when the request is completed, and it's sent a parameter with the value sent from the server.
If you are not familiar will callback functions, it may be clearer if you declare a regular function an use as the callback:
function fulfilled(result) {
if (result.status === 200) {
resDiv.style.backgroundColor = "lightGreen";
resDiv.innerText = "Success";
}
}
WinJS.xhr({ url: "http://someurl.com" }).then(fulfilled);
The then method is intended for pre-processing the result, you should rather use the done method to take care of the result.
I haven't found anything in the documentation that specifies exactly in what form the value comes from the server. It's probably there somewhere, but as usual with Microsoft documentation, it's rather complete but everything isn't everywhere so you have to look in different places to find specific information.
I'm totally new to javascript and have difficulty in understanding the meaning of the scripts. :( Hope someone can help me or give some advice, thaks! :)
I have a javascript in which it call Ajax function like:
callAjax('../team.cgi', 'POST', data, function(text)
In the ajax2.js it define the function callAjax like:
function callAjax(url, method, data, handler, waittime, timeout_func)
My question is what's the parameter function(text)?
function(text) is the beginning of the definition of an anonymous function. Presumably the call looks something like this:
callAjax('../team.cgi', 'POST', data, function(text)
{
// do something with text
});
The function defined between those brackets takes a variable, text, and does something with it. This is possible in JavaScript because functions are first-class citizens. They can be assigned to variables, defined anonymously, etc.
Typically, you'd say the handler parameter of the callAjax function is a callback. It's a function that will be passed certain arguments when the Ajax call completes. This is typical of asynchronous code.
The snippet above is functionally the same as this:
function doSomethingWhenAjaxCompletes(text) {
// do something
}
callAjax('../team.cgi', 'POST', data, doSomethingWhenAjaxCompletes);
The only difference in the first is that the function isn't defined with the name doSomethingWhenAjaxCompletes; it's defined anonymously instead.
Without seeing the context of the handler function my guess would be that this is the returned value from the ajax call. For example, if team.cgi in your example above returns an xml list of teams then I would expect the text parameter in the handler function to be that list.
When issuing AJAX requests, execution does not halt and wait for the response to come back. Instead, the request is send and execution continues. You simply provide what is called a "callback" function which is called when the AJAX response is returned. Typically, the callback function takes a single argument containing the response object or message that was returned as the answer to your AJAX request.
callAjax('../team.cgi', 'POST', data, function(text) {
console.log('Got a response!');
console.log(text);
}
This simply sends the request. At some time later (after a pause due to network latency) you will see the console log message appear, indicating that a response was received and the callback function meant for "handling" the response has been called.