3

I'd like to append to an element and have it update immediately. console.log() shows the data as expected but append() does nothing until the for loop has finished and then writes it all at once.

index.html:

...
<body>
    <p>Page loaded.</p>
    <p>Data:</p>
    <div id="Data"></div>
</body>

test.js:

$(document).ready(function() {
    for( var i=0; i<5; i++ ) {
        $.ajax({
            async: false,
            url: 'server.php',
            success: function(r) {
                console.log(r); //this works
                $('#Data').append(r); //this happens all at once

            }
        });
    }
});

server.php:

<?php 
    sleep(1);
    echo time()."<br />";
?>

The page doesn't even render until after the for loop is complete. Shouldn't it at least render the HTML first before running the javascript?

1
  • 1
    why do you use async: false? Commented Oct 31, 2013 at 3:56

1 Answer 1

4

If you switch to async: true, then the screen will be able to update as you append data.

$(document).ready(function() {
    var cntr = 0;
    // run 5 consecutive ajax calls
    // when the first one finishes, run the second one and so on
    function next() {
        $.ajax({
            async: true,
            url: 'server.php',
            success: function(r) {
                console.log(r); //this works
                $('#Data').append(r); //this happens all at once
                ++cntr;
                if (cntr < 5) {
                    next();
                }

            }
        });
    }
    next();
});

If you insist on using async: false (which is generally horrible), then you could put a short setTimeout() between each ajax call and the screen would update during the timeout.

There are also some hacks that "may" cause the screen to update (no guarantees) by accessing certain CSS properties that can only be calculated when the HTML layout is up-to-date which may causes the browser to display the latest changes. I say "may" because this is not by specification, only an observation of behavior in some browsers. You can read more about this option here.

In any case, since you're already using ajax calls, the best way to solve this here is to use async: true and change your loop construct to one that will work with the async ajax call (as I've shown in my example).

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks! I want to use async: false because I'm actually doing some screen scraping and don't want to slam the server. Can you explain why the loop needs to be like this and not a simple for loop?
A simple for loop combined with async: true will launch all 5 ajax calls immediately and then all 5 results will come in. It will send a burst of requests to the server. Doing it the way I did will send one, wait for the response, when it gets that first response, send the second and so on, not slamming the server. So, you can use my way with async: true and not slam the server.
Okay that makes sense. Thanks for your answers, this was driving me crazy! I'm still unclear though why the for loop and async: false doesn't achieve the same thing. Is it jquery or the browser (in this case chrome) that's delaying the render?
@david_nash - Browsers try to coalesce all DOM changes into one layout and one repaint because that performs much better (relayout and repaint is slow). So, if a thread of JS is still running, the browser is waiting for it to be done before they repaint the screen. When you use async: false, the JS thread is continually running and not finished, thus the browser is still waiting until your last ajax call is done. It wouldn't have to be that way, but that's the way it works.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.