With jQuery Message Queuing you can manage a large queue of asynchronous requests, forcing their execution to be serial. Normally, you'd use a system like this to effectively throttle high volumes of AJAX requests (or other asynchronous actions).

This example is a purely visual representation of how this type of asynchronous-but-serial queue might execute.

Let's get to it!

In this example, whenever the queue callback is executed, an AJAX request is made, and an orange "request" box is added. If the response is unsuccessful, the orange box is replaced with a red box, and another attempt is made. If the response is successful, the orange box (and any red boxes) are replaced with a green box. When the queue becomes empty due to its natural completion (and not being explicitly cleared), a grey "done" box is added.

You may hover over any numbered item to add it to the queue, and you may also pause, start or clear the queue, as well as change the queue's batch size.

Last item: N/A, Size: 0
pending request response success response error queue completed

The code

$(function(){
  
  // Create a new queue.
  window.queue = $.jqmq({
    
    // Next item will be processed only when queue.next() is called in callback.
    delay: -1,
    
    // Process queue items one-at-a-time.
    batch: 1,
    
    // For each queue item, execute this function, making an AJAX request. Only
    // continue processing the queue once the AJAX request's callback executes.
    callback: function( item ) {
      $('#output')
        .append( '<span class="pending">' + item + '<\/span>' )
        .find('.done')
          .remove();
      
      // Update the "Size" display.
      set_size();
      
      // Make a JSON request. The response will return a success boolean as well
      // as some HTML.
      $.getJSON( 'action.php?items[]=' + item, function(data){
        $('#output')
          .append( data.html )
          .find('.pending')
            .remove();
        
        data.success && $('#output .error').remove();
        
        // If the request was unsuccessful, make another attempt.
        queue.next( !data.success );
        
        // Update the "Size" display.
        set_size();
      });
    },
    
    // When the queue completes naturally, execute this function.
    complete: function(){
      $('#output').append( '<span class="done">done<\/span>' );
    }
  });
  
  // Disable AJAX caching.
  $.ajaxSetup({ cache: false });
  
  // On mouseover, add an item to the queue.
  $('#items a').mouseover(function(){
    var item = $(this).text();
    queue.add( item );
    
    // Update the "Last" display.
    set_last( item );
    
    // Update the "Size" display.
    set_size();
  });
  
  // Bind queue actions to nav buttons.
  
  nav( 'Pause', 'Queue paused.', function(){
    queue.pause();
  });
  
  nav( 'Start', 'Queue started.', function(){
    queue.start();
  });
  
  nav( 'Clear', 'Queue cleared.', function(){
    queue.clear();
  });
  
  nav( 'Batch = 1', 'Queue batch size set to 1.', function(){
    queue.update({ batch: 1 });
  });
  
  nav( 'Batch = 4', 'Queue batch size set to 4.', function(){
    queue.update({ batch: 4 });
  });
  
});