views:

821

answers:

4

Here's a very simple Prototype example.

All it does is, on window load, an ajax call which sticks some html into a div.

<html>
    <head>
        <script type="text/javascript" src="scriptaculous/lib/prototype.js"></script>
        <script type="text/javascript">
            Event.observe(window, 'load', function(){
                new Ajax.Request('get-table.php', {
                    method:  'get',
                    onSuccess:  function(response){
                        $('content').innerHTML = response.responseText;
                        //At this call, the div has HTML in it
                        click1();
                    },
                    onFailure:  function(){
                        alert('Fail!');
                    }
                });
                //At this call, the div is empty
                click1();
            });

            function click1(){if($('content').innerHTML){alert('Found content');}else{alert('Empty div');}}
        </script>
    </head>
    <body><div id="content"></div></body>
</html>

The thing that's confusing is the context in which Prototype understands that the div actually has stuff in it.

If you look at the onSuccess part of the ajax call, you'll see that at that point $('content').innerHTML has stuff in it.

However when I check $('content').innerHTML right after the ajax call, it appears to be empty.

This has to be some fundamental misunderstanding on my part. Anyone care to explain it to me?


Edit
I just want to clarify something. I realize that the Ajax call is asynchronous.

Here's the actual order that things are being executed and why it's confusing to me:

  1. The page loads.
  2. The Ajax request to get-table.php is made.
  3. The call to click1() INSIDE onSuccess happens. I see an alert that the div has content.
  4. The call to click1() AFTER the Ajax call happens. I see an alert that the div is empty.

So it's like the code is executing in the order it's written but the DOM is not updating in the same order.


Edit 2 So the short answer is that putting the code in onSuccess is the correct place.

Another case to consider is the one where you do an Ajax call and then do another Ajax call from the onSuccess of the first call like this:

new Ajax.Request('foo.php',{
  method:  'get',
  onSuccess:  function(response){
    doAnotherAjaxCall();
  }
  });

function doAnotherAjaxCall(){
  new Ajax.Request('foo.php',{
    method:  'get',
    onSuccess:  function(response){
      //Anything that needs to happen AFTER the call to doAnotherAjaxCall() above
      //needs to happen here!
    }
  });
}

});

+5  A: 

The first letter of AJAX stands for "asynchronous". This means that the AJAX call is performed in the background, i.e. the AJAX request call immediately returns. This means that the code immediately after it is normally actually executed before the onSuccess handler gets called (and before the AJAX request has even finished).

Taking into account your edited question: in some browsers (e.g. Firefox), alert boxes are not as modal as you might think. Asynchronous code may pop up an alert box even if another one is already open. In that case, the newer alert box (the one from the asynchronous code) gets displayed on top of the older one. This creates the illusion that the asynchronous code got executed first.

Jan Krüger
Please read my edit. The flow you're describing is not entirely accurate in practice.
Mark Biek
You're partly right :) Firefox definitely behaves the way you're describing.IE7 though, displays the alert from inside onSuccess first which is very confusing.
Mark Biek
I can't confirm that. IE7 does exactly the same thing as Firefox on my computer, except that the dialogs pop up in different places so you can actually see what's going on.
Jan Krüger
A: 

Without having tried your code: The AJAX call is executed asynchronously. Meaning that your Ajax.Request fires, then goes on to the click1() call that tells you the div is empty. At some point after that the Ajax request is finished and content is actually put into the div. At this point the onSuccess function is executed and you get the content you expected.

_Lasar
A: 

It's Ajax call, which is asynchronous. That means right after that request call, response hasn't come back yet, that's why $('content') is still empty.

A: 

The onSuccess element of the function call you are making to handle the AJAX call is executed at the time you receive a response from get-table.php. This is a separate Javascript function which you are telling the browser to call when you get an answer from get-table.php. The code below your AJAX.Request call is accessed as soon as the AJAX.Request call is made, but not necessarily before get-table.php is called. So yes I think there is a bit of a fundamental misunderstanding of how AJAX works, likely due to using a library to hide the details.

Stimy