2
       var hasData = '1';
        while (hasData != 0) {
            $.ajax({
            url: '/ajax.php?updateRow='+hasData,
            dataType: 'json',
            async: false,
            success: function(data) {
                hasData = data.next;
                $('.result').append(data.html);
              }
            });

What should happen: JSON Array pulled from PHP ( [html] and [next] ). If [next] is set to 0 (when there are no more entries) - the while loop stops and that should be it.

What happends: Everything that should, except - when the while() requirement is met (so when hasData is set to 0) - the loop enters into an infinite loop (and it keeps requesting the last entry, forever...until the script becomes "unresponsive")

emboss
  • 38,880
  • 7
  • 101
  • 108
pyronaur
  • 3,515
  • 6
  • 35
  • 52
  • 9
    Ajax requests are asynchronous! – Richard H Aug 15 '11 at 11:07
  • 4
    Not if you've set 'async: false', however. Unless we're being pedantic about the name, in which case we should also be telling him to use XML... – Grim... Aug 15 '11 at 11:12
  • 3
    Synchronous Ajax requests let the browser's UI be unresponsive during the request. **Never** use `async:false`. – duri Aug 15 '11 at 11:18
  • 2
    That's good advice, but doesn't really solve the problem (in fact, making the above code asynchronous would make the problem a lot worse). – Grim... Aug 15 '11 at 11:25

5 Answers5

6

ajax sends a request and executes the callback when there is a response. So what's happening is:

  • fire a request
  • fire another request
  • fire another request
  • fire another request
  • ...

because it's inside a while loop. You're clogging your script up with requests, and the server gets a bunch of requests which it probably cannot handle.

Edit: I'm sorry, I missed async: false. However that always makes the browser irresponsive. The best thing to do would be using async: true and fire another if the conditional says so, but only after you get the response:

function check() {
        $.ajax({
        url: '/ajax.php?updateRow='+hasData,
        dataType: 'json',
        async: true,
        success: function(data) {
            hasData = data.next;
            $('.result').append(data.html);
            if(hasData != 0) check(); // do it again
          }
        });
}

check(); // fire the first request

As Spycho pointed out, since you're fetching JSON, a more convenient way might be:

(function() {

    var fireRequest = function() { // this function is not available anywhere else,
                                   // to avoid having this process running more than once

        $.getJSON('/ajax.php', {updateRow: hasData}, function(data) {
            hasData = data.next;
            $('.result').append(data.html);
            if(hasData != 0) fireRequest(); // do it again
        });

    };

    fireRequest(); // start the process

})(); // call it
pimvdb
  • 151,816
  • 78
  • 307
  • 352
  • 1
    You might want to switch from using $.ajax to [$.getJSON](http://api.jquery.com/jQuery.getJSON/), as it's a little neater and would make an identical request. – Spycho Aug 15 '11 at 11:26
  • 1
    I think you have a typo in your answer. You recommended `async: true` and then wrote `async: false` in your solution. – Spycho Aug 15 '11 at 11:30
  • @pimvdb: I'm just curious, is there a reason why you used `arguments.callee` instead of just naming the function in your recursive example? – user113716 Aug 15 '11 at 12:05
  • @patrick dw: I thought it would be putting the function into the global object that way. I see it actually does not. `(function a() {})` does not put `a` into `window.a`, wouldn't expect that. Naming it would be a better choice indeed, thanks. – pimvdb Aug 15 '11 at 12:07
  • @pimvdb: Unfortunately it actually does in IE8 and below because of a bug with their named function expressions, but then `arguments.callee` will throw a `TypeError` in "strict mode". +1 for the recursive solution though. – user113716 Aug 15 '11 at 12:11
  • Okay, thanks. I'm new to JavaScript and AJAX. Quick question tho - @pimvdb - What does the (function() { ... })(); do ? Never seen empty parentheses alone - in programming before. I am calling the function to display content from in the middle of the page ( – pyronaur Aug 15 '11 at 12:42
  • @Methemer: It creates a function, and calls itself. It's a function wrapped inside `(` and `)` and then executed directly using `()`. That way, you can call a function without putting it into a variable so that the function cannot be called any more times. – pimvdb Aug 15 '11 at 12:44
4

Actually, what your code does is not far from a Denial of Service attack on your own server :)

The Ajax requests won't block until they are finished, as the others already pointed out. Calling $.ajax returns immediately, the actual request is executed in the background and calls the success callback upon completion. This all means that Javascript loops through the while as fast as it can, because nothing stops it. This also means that while your first request tries to finish, Javascript has probably spawned thousands of new requests which all need to be processed by the server.

Your server will become uncomfortable serving so many requests at the same time and slows down (if you check it's CPU and memory usage, you will notice). Because of the server slowing down Javascript will spawn ever more and more requests... until finally the whole system grinds to a halt because Javascript is running out of resources and your server probably, too.

A while loop is not recommended in your case. It's better to send one request at a time and check for the return value inside the success callback. If it's not 0 yet, spawn another request, and repeat the procedure.

function updateRows(onCompleted) {
    $.ajax({
        url: '/ajax.php?updateRow='+hasData,
        dataType: 'json',
        success: function(data) {
            hasData = data.next;
            if (hasData == 0) {
               return onCompleted();
            }    

            $('.result').append(data.html);
            updateRows(onCompleted); // not finished yet, recursion
        }
    });
}

The onCompleted argument would be a callback function that gets executed once your update procedure is completed. You could use it as follows:

updateRows(function() {
    // Now all rows are updated
    // Proceed with program flow
});
emboss
  • 38,880
  • 7
  • 101
  • 108
1

The first A letter in AJAX means "asynchronous". The browser doesn't wait for the response after the initial $.ajax() call, but calls this function many many times.

var hasData = 1;
function ajaxRequest()  {
    $.ajax({
        //...
        success: function(data) {
            hasData = data.next;
            $('.result').append(data.html);
            if (hasData != 0)
            {
                ajaxRequest();
            }
        }
    });
}
duri
  • 14,991
  • 3
  • 44
  • 49
0

also I suggest you cast your response data to number like

hasData = data.next * 1;

as sometimes even if JSON returns a number, its not considered to be a number by javascript and comparison

hasData != 0

comes true even if hasData="0" ...

Radek
  • 519
  • 5
  • 16
0

Because you have set async to false the browser will hang until a response is available. It's possible that your script is not stuck in an infinite loop, it just waits for the response.

Check that your server side script actually works.

Felix Glas
  • 15,065
  • 7
  • 53
  • 82