1

I have the following Javascript and it's returning results out of the order I would expect them.

function getCurrentItems(id){
    alert("2");
    $.ajax({
        url: "somePHPurlthatspitsoutajsonencodedArray.php",
        type: "POST",
        dataType: "json'",
        data: {id:id},
        success: function(data){
            alert("3");
        }
    });
    alert("4");
}

$(document).on('click', '.eventClass', function(e){
    alert("1");
    var id = "someID";
    var results = getCurrentItems(id);
    alert("5");
});

I would think I'd get alerts in the order of 1, 2, 3, 4, 5.

Instead I get them in the order of 1, 2, 4, 5, 3.

I just can't figure out why that success alert (5) fires last?

chrisjacob
  • 170
  • 12
  • 8
    Welcome to the wonderful world of asynchronous javascript. – Kevin B Apr 24 '15 at 21:17
  • 2
    http://stackoverflow.com/questions/4559032/easy-to-understand-definition-of-asynchronous-event – epascarello Apr 24 '15 at 21:19
  • @WilfredoP I was getting frustrated so I just resorted to alerts...lol – chrisjacob Apr 24 '15 at 21:19
  • 1
    Well if you are starting with ajax what you could try to do is write `async: false` in the options of your ajax – Jorge F Apr 24 '15 at 21:19
  • 2
    @JorgeF `async: false` is never the answer. – Evan Davis Apr 24 '15 at 21:20
  • @JorgeF that did it. I've never had a problem with this until now. – chrisjacob Apr 24 '15 at 21:21
  • 2
    @JorgeF Yeah that's really bad advice. It would only mask the real issue and effectively prevent them from learning how things actually work. – JJJ Apr 24 '15 at 21:21
  • http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-asynchronous-call – meteor Apr 24 '15 at 21:21
  • 6
    @chris72205 do not use `async: false` learn how to deal with asynchronous events. http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-asynchronous-call – epascarello Apr 24 '15 at 21:22
  • That occur because $.ajax create an async promise that is resolved/rejected when it get a result from the server, so, this means that the execution isn't blocked waiting the ajax call to succeed to execute the rest of the code. You should read about event loop and promises. – ecarrizo Apr 24 '15 at 21:25

3 Answers3

4

AJAX is short for asynchronous JavaScript and XML. Asynchronous is the keyword here. I'll use an allegory to explain async.

Lets say you're washing dishes manually. You can't do anything else while doing that, so it is synchronous.

Lets say you put your dishes in a dishwasher. You can do other things, you've delegated the task to the dishwasher, so this is asynchronous. Asynchronous is generally better, because you can do multiple things at one time. Javascript only asyncs when requesting info from the server, as Javascript is single threaded (it only runs on 1 CPU core and can only do one thing at a time on it's own).

A callback is a function that is called when the async task completes. The dishwasher finishes, so now you have to empty it as soon as you complete what you're doing when it finshed.

So in your code, you start the dishwasher, say you're going to alert("3") when the dishwasher finishes running, and then you go alert 4 and 5. Then when the dishwasher finishes/your server returns data, you alert 3 like you said you would.

That make sense?

James G.
  • 2,852
  • 3
  • 28
  • 52
  • Perfect explanation, thank you! – chrisjacob Apr 24 '15 at 21:28
  • Nice answer but Javascript is not only async when making request. – ecarrizo Apr 24 '15 at 21:55
  • Making requests isn't the only time JS uses callbacks, but it's the only time JS is async. JS cannot run async unless it is requesting external resources. What do you mean @ecarrizo? – James G. Apr 24 '15 at 21:58
  • 1
    Just try this and you would understand this is also async https://jsfiddle.net/zapqkpkz/ there are other ways to approach that behavior like promises and ita not needed to request for external resources.. In fact ajax is async because the way that the code was wrote not for what the code is doing – ecarrizo Apr 24 '15 at 22:07
  • 1
    @ecarrizo I wouldn't have considered setTimeout to by async, but yep, it and setInterval meet all the requirements, nice catch. – James G. Apr 24 '15 at 22:19
3

The reason that you give a success callback function in an ajax request is that the request might take some time to return, but your code can continue running. In this case the ajax request is sent, and the success function is remembered for later, then your code continues (alerting 4 and 5). When the browser receives the response to the ajax request it calls the success function (alerting 3).

The way that Javascript works, only one thread is run per browser tab, so event handlers are not called until any previously running code is completed. Therefore, even if your getCurrentItems function were to take several seconds to complete, by which time the server response had returned, the success function would still not be called until after your function had completed.

Edit: Because an ajax call can take some time, it is not generally desirable to be able to call a function like getCurrentItems which includes an ajax request, and wait for the response. If you do this, then you are likely to leave your browser window unresponsive, and you will have to deal with potential errors from the ajax call. Instead, you should put any code that you wish to run which relies on the ajax result in the success function, or in another function which you call from there. As languages go, Javascript is very good for doing this kind of thing. You could even take a callback function as an argument to getCurrentItems, and run it from the success function.

gandaliter
  • 9,863
  • 1
  • 16
  • 23
-1

As others have mentioned, you're getting the results in the order you see because the ajax request doesn't return with it's data and call your success callback until the response is received, but code continues to execute immediately after the $.ajax call.

To get the workflow you're probably expecting, you could use promises, or simply pass in a callback:

function getCurrentItems(id, onSuccess){
    alert("2");
    $.ajax({
        url: "somePHPurlthatspitsoutajsonencodedArray.php",
        type: "POST",
        dataType: "json'",
        data: {id:id},
        success: function(data){
            alert("3");
            onSuccess(data);
        }
    });
    alert("4");
}

$(document).on('click', '.eventClass', function(e){
    alert("1");
    var id = "someID";
    var results = getCurrentItems(id, function(data){
       console.log('data',data);
       alert("5");
    });

});
Allan Nienhuis
  • 3,961
  • 2
  • 23
  • 19
  • 1
    Re-read the question – posit labs Apr 24 '15 at 21:22
  • The OP knows what is happening. They are asking **why** it is happening. – Norman Breau Apr 24 '15 at 21:24
  • ok, this will return the result in 1,2,4,3,5. I was focused the part that suggested he wanted the 5 the last result... Perhaps I missed something else? re-read the question doesn't give me a lot to work on... – Allan Nienhuis Apr 24 '15 at 21:25
  • This is a workaround to solve the problem that he is having, but he like to know WHY he get that result. If you add an explanation before the solution this would be a real answer to the question with a possible workaround (your code suggestion). – ecarrizo Apr 24 '15 at 21:28
  • @NormanBreau - thanks, that was better feedback. He was asking why. I gave him a answer that would probably get him the result he was looking for in the first place. – Allan Nienhuis Apr 24 '15 at 21:28
  • 1
    @ecarrizo thanks for the feedback - I'll add some more detail. – Allan Nienhuis Apr 24 '15 at 21:29