Lee
Lee

Reputation: 5936

PHP, jQuery & Ajax calls out of order

I am using jQuery for my Ajax calls... I have x amount of Ajax calls that append to a div. These Ajax load requests are generated by a PHP foreach loop... The problem is they render out of the order; they are set in the array...

<script type="text/javascript">
function loadPage(target, url, append)
{
    if (append == true) {
        $.get(url, function(data) { $(target).append(data) });
    }
    else {
        $(target).load(url);
    }
    return false;
}
</script>

////// ----- PHP

<?php
    $this->data['sidebar']  = array('login', 'active_leagues', 'latest_forum_threads', 'latest_matches', 'sponsors');

    if (isset($sidebar[0]) && !empty($sidebar[0]))
    {
        echo '<div class="right_col">';
        foreach($sidebar as $val)
        {
            echo "<script>loadPage('.right_col', 'http://dev.banelingnest.com/sidebar/". $val ."', true)</script>";
        }
        echo '</div>';
    }

I am wonder if the cause of this is the web server responding slower to some requests than others... Other than that, I have no clue why this could be happening. Do you have any thoughts how I could keep the requests in order?

Upvotes: 2

Views: 2891

Answers (7)

fr3nch13
fr3nch13

Reputation: 61

Here is what I did with the array or urls I needed to load in order. I created the order of wrappers first, than did the ajax calls, and load the results into the matching wrapper. This keeps the calls asynchronous, but you still the the proper order.

$.fn.dashboarder = function(options) 
{
    var settings = $.extend({ 
        urls:        [],
    }, options || {});

    var self = this;

    if (settings.urls.length) 
    {
        $(self).html('');
        /// create wrapper blocks in the proper order, so they eventually display in this order
        $(settings.urls).each(function( index, value ) 
        {
            var wrapper = $( "<div />" )
                .addClass('dashboard-block-item')
                .attr('id', 'dashboard-block-item-'+index);
            $(self).append($(wrapper));
        });

        $(settings.urls).each(function( index, value ) 
        {
            $('#dashboard-block-item-'+index).load(value, function( response, status, xhr ) 
            {
            }).delay(5000 * index);
        });

    }

    return this;
}

function debug( obj ) {
    if ( window.console && window.console.log ) {
        window.console.log( obj );
    }
};

Upvotes: 0

Tgr
Tgr

Reputation: 28200

The simplest solution is creating placeholders, as inti described. Your elements will not necessarily appear in order, but they will end up in the right order. If you need them to appear in order too, here is a simple queue using deferreds:

var queue = [];
function loadPage(target,url) {
    queue.push($.get(url));
    $.when.call($, queue).then(function() {
        $(target).append(Array.prototype.pop.call(arguments));
    });
}

The AJAX calls will run in parallel, but the callbacks will fire strictly in order.

Upvotes: 0

Fosco
Fosco

Reputation: 38526

This is happening because the ajax calls are asynchronous, and the order they go out has nothing to do with the order they are returned. They will all happen independently and it's expected for some to run faster than others.

You will need to use $.ajax instead of $.get, and set async to false.

See this question: How can I get jQuery to perform a synchronous, rather than asynchronous, Ajax request?

You can also use the unique and interesting solution presented by @inti.

Upvotes: 3

Ryan
Ryan

Reputation: 1888

I have 2 ideas that may help, the first is:

jQuery has a $(document).ready(function() function that is possibly being called from a parent function or being inherited somehow, this means the JavaScript won't run before the rest of the PHP has loaded.

I have seen some functions inherit this from jQuery without it being declared.

The second is: I am assuming that this function is running in the head or early on in your page and not the foot or later on in the document.

I hope they help.

Upvotes: 1

aorcsik
aorcsik

Reputation: 15552

You have to create reference points before the requests, and append the results to them:

var counter = 0;

function loadPage(target,url,append)
{
    if (append == true) {
        var id = "container_"+counter;
        $(target).append("<div id='"+id+"'></div>")
        $.get(url, function(data) { 
            $("#"+id).append(data);
        });
        counter++;
    } else {
        $(target).load(url);
    }

    return false;
}

Your reference elements will be appended to the target on every loadPage() call, so they will be in the correct order, and the request can come in any order they will be loaded in their right place.

Upvotes: 6

Marc B
Marc B

Reputation: 360792

You could do synchronous requests instead of asynchronous, which'd force the browser to wait until each individual request finishes before starting the next. The downside that is for any "lengthy" requests (or many short ones), the browser will be locked up.

You may want to investigate sending all your requests in a single AJAX call, rather than doing one-request-per-call. That way it'd be easy for the scripts on both sides to keep everything in order. Otherwise you're stuck depending on the user link to your server having low error rates, low latency, and low congestion.

So instead of doing the equivalent of

loadPage(1); // fetch data #1
loadPage(37); // fetch data #37
loadPage(203); // fetch data #203

do something like

loadPage([1,37,203]); // fetch all 3 at once.

Upvotes: 1

AC2MO
AC2MO

Reputation: 1637

This is the nature of AJAX, and yes the server is responding faster to some than others.

If you want them in order, you would have to make the first call, then on the complete event, call the next one, and so on; in essence creating a synchronous chain of calls (kind of goes against the A in AJAX).

Without knowing your specific reasons for wanting them in order, this may be a lot more work than what it's worth.

However you do it, it will take away from the user experience, because if one call is slow, all of the other will have to wait.

Upvotes: 0

Related Questions