Experimenting With jQuery's Queue() And Dequeue() Methods

Posted March 2, 2010 at 9:10 AM by Ben Nadel

Tags: Javascript / DHTML

jQuery comes with a number of built-in animation methods like slideUp() and slideDown(). While these appear to be packaged in their own methods, many of them are powered internally by the animate() method. And while the animate() method handles many of the effects, a string of sequential animations is controlled internally by jQuery's queuing mechanism. This queuing mechanism, while used primarily for the FX ("effects") queue, is also made available as part of the jQuery API. This API allows programmers to manage arbitrary queues for anything that needs to happen sequentially.

 
 
 
 
 
 
 
 
 
 

I have never used the queuing mechanism before, so I thought I would do some experimentation. There are two main methods that control a particular queue: queue() and dequeue(). While these methods can be accessed off of the jQuery namespace, they are designed to be associated with a given element or object. So, you can think of a queue as not just a series of events, but rather as a series of events that take place in the context of a given object.

To add an action to a queue, you have to tell the queue() method the name of the queue (the default queue is the "fx" queue) and the callback to be executed as the queue item. jQuery does not have any insight into how the queue items function; as such, we need to explicitly tell jQuery when to move to the next item in the queue. This can be done in two ways: first, you can call the dequeue() method on the given element with the given queue name. This works, but requires you to use the queue name which becomes yet another data point to maintain over time. The second, more optimal way, is to use the next() function that jQuery passes to your queue item callback. The next() function encapsulates the dequeue() method and the queue name into a single point of execution.

While the jQuery "fx" animation queue starts to execute immediately (dequeues itself), explicitly managed queues do not. As such, after we build up our queue items, we have to call dequeue() on the queue in order to kick off the series of sequential events. To see this in action, I have set up a small test page:

  • <!DOCTYPE HTML>
  • <html>
  • <head>
  • <title>jQuery Queue And Dequeue</title>
  • <script type="text/javascript" src="../jquery-1.4.2.js"></script>
  • <script type="text/javascript">
  •  
  • // When the DOM is ready, initialize scripts.
  • jQuery(function( $ ){
  •  
  • // Get a handle on the paragraph we want to update.
  • var para = $( "p:first" );
  •  
  • // Add the first queue item. Unlike the native animation
  • // methods, manually created queue items don't start
  • // executing right away - we have to manually call the
  • // dequeue() method at the end.
  • para.queue(
  • "testQueue",
  • function( next ){
  • para.html( "This is queue item #1: Hot" );
  •  
  • // Each queue method is passed a "next" method
  • // reference. This method encapsulates the
  • // name of the queue into a function. This way
  • // we can dequeue the current queue without
  • // having to know its name.
  • next();
  • }
  • );
  •  
  • // Delay the queue for a bit.
  • para.delay( 1500, "testQueue" );
  •  
  • // Add the next queue item.
  • para.queue(
  • "testQueue",
  • function( next ){
  • para.html( "This is queue item #2: Sexy" );
  • next();
  • }
  • );
  •  
  • // Delay the queue for a bit.
  • para.delay( 1500, "testQueue" );
  •  
  • // Add the next queue item.
  • para.queue(
  • "testQueue",
  • function( next ){
  • para.html( "This is queue item #3: Sleezy" );
  • next();
  • }
  • );
  •  
  •  
  • // ---------------------------------------------- //
  •  
  •  
  • // When we have our queue set up, we have to manually
  • // dequeue the first item to get the queue to start
  • // processing.
  • para.dequeue( "testQueue" );
  •  
  • });
  •  
  • </script>
  • </head>
  • <body>
  •  
  • <h1>
  • jQuery Queue And Dequeue
  • </h1>
  •  
  • <p>
  • This is where the queue output will go.
  • </p>
  •  
  • </body>
  • </html>

As you can see, I am using both the queue() method and the delay() method to build up my, "testQueue", queue. The delay() method, while typically used with animation queues, can be used to add an arbitrary pause to any queue event series. Once I have built up the queue, I use the dequeue() method to kick off the queue events.

jQuery's queuing mechanism seems very cool but, I am not sure what I would use it for outside of the native animation methods. I would certainly love to hear how other people might leverage this functionality.


You Might Also Be Interested In:



Reader Comments

Mar 2, 2010 at 9:47 AM // reply »
19 Comments

It's especially useful when have a series of asynchronous method calls that you want to execute serially, and don't want to maintain a chain of callbacks.

Say you want to execute first_async_action() followed by second_async_action(), followed by third_async_action(). You could do this:

<pre>
first_async_action(function(){
second_async_action(function(){
third_async_action(function(){
alert( 'done!' );
});
});
});
</pre>

Or if that looks messy (which it does) you could try something like this:

<pre>
function start(){
first_async_action( exec_second_async_action );
};

function exec_second_async_action(){
second_async_action( exec_third_async_action );
};

function exec_third_async_action(){
third_async_action( all_done );
};

function all_done(){
alert( 'done!' );
};
</pre>

start();

But what if you decide you need to execute third_async_action before second_async_action? either way, it's messy.

A good, flexibile, solution would be to do this kind of thing:

<pre>
function next(){
var action = actions[ idx++ ];
action && action();
};

var idx = 0,
actions = [
function(){
first_async_action( next );
},
function(){
second_async_action( next );
},
function(){
third_async_action( next );
},
function(){
alert( 'done!' );
}
];

next();
</pre>

Which is pretty much what jQuery's queuing methods do, internally.


Mar 2, 2010 at 9:47 AM // reply »
19 Comments

Man, I wish there was comment code syntax highlighting.


Mar 2, 2010 at 9:52 AM // reply »
10,748 Comments

@Cowboy,

Yeah, sorry about this code formatting in the comments. Never really got that nailed down quite nicely (read: at all). I'll try to make some time for that.

I see what you're saying about the sequential AJAX calls. Typically, in my apps, when I need to make sequential AJAX calls, the calls are highly coupled; meaning, the execution of the second relies heavily on the successful execution of the first. I think it would be much less likely that I would simply need to fire things sequentially.

Although, I suppose I could always clear the queue if one of the calls came back in a particular way. But even then, I wonder if my code would lose some readability?


Mar 2, 2010 at 10:09 AM // reply »
19 Comments

@Ben, I like SyntaxHighlighter personally.. you can see it in my site's comments, plugin code examples, etc. Easy to use and flexible.

http://alexgorbatchev.com/wiki/SyntaxHighlighter

Regarding the queueing stuff, I actually wrote a plugin to manage queues, but it works a bit differently than jQuery's built in queue methods. You don't use it specifically on jQuery objects, for example.

http://benalman.com/projects/jquery-message-queuing-plugin/

Still, it really makes a lot of sense to use a managed queue internally for all these animation methods, because it eliminates the whole "ridiculous nested callback" scenario.. and of course, because the queue manager is iterating over an array of queued items, it's trivial to skip a queue item or stop the queue at any time.


Mar 2, 2010 at 10:14 AM // reply »
19 Comments

BTW, here's my code as a gist for easier viewing:
http://gist.github.com/319568


Mar 2, 2010 at 10:28 AM // reply »
7 Comments

@Ben and @Cowboy, thanks for sharing this info. I'm fairly new to jQuery. Thus far I have only really used it for dynamic drop down population, but I would like to branch out into using more of it.


Mar 2, 2010 at 7:59 PM // reply »
10,748 Comments

@Cowboy,

I like the syntax highligher; unfortunately, my WYSIWYG editor (XStandard) does not allow for PRE tags. I am not sure of Script tags though, I should check into that.

Maybe I'll take a look at the way it works and see if I can port it over to the ColdFusion side. Right now, I do my formatting on Database-insert so it's only done once.

@James,

jQuery is wicked awesome! Once you start learning it, you'll be hooked!


Jun 17, 2010 at 6:14 PM // reply »
2 Comments

@Cowboy,
Could you please explain the code you written?
I was trying to follow your example, but failed (( Here is my code. Probably you could tell me where I got something wrong
Thanks!

$('.child').bind('click', function(){
var $anchor = $(this);
function next(){
var action = actions[ idx++ ];
action && action();
};

var idx = 0,
actions = [
function(){
$(function (next) {$anchor.hide('fast');});
},
function(){
$(function (next) {$anchor.show('fast');});
},
function(){
$(function (next) {$anchor.hide('fast');});
},
function(){
alert( 'done!' );
}
];

next();

});


Jun 17, 2010 at 6:46 PM // reply »
19 Comments

@tylik, it might be more helpful if you fork my gist on GitHub and ask your question there, so that we get the benefit of syntax highlighting, indenting, comments and revisions.

http://gist.github.com/319568


Jul 18, 2010 at 2:00 PM // reply »
4 Comments

Brilliant example! Though its a very simple example, I used the concept for a complicated Ajax system which had multiple steps that should be executed serially reporting the status of each step to the DOM. Amazing and a big thanks to you and your great highlights.


Jul 20, 2010 at 9:51 PM // reply »
10,748 Comments

@Mahesh,

Sounds like you found a really cool use of queue() and dequeue(). Glad that I might have provided some value in that.


Feb 12, 2012 at 9:29 AM // reply »
1 Comments

Great information


Feb 13, 2012 at 9:08 PM // reply »
4 Comments

Hello Ben,

This is just awesome, clear and easy to follow.

It helped me in a project I am doing,

Your site has become an authority on Ajax coding,

2 Thumbs up from me :)

Many Thanks,
Nader.


Feb 22, 2012 at 1:38 PM // reply »
1 Comments

Excellent explanation, thanks for the post. I have only one question, how do i get to the last effect in queue without execute others effect.


Apr 12, 2012 at 6:34 AM // reply »
1 Comments

Hi,

I have read lots of your tutorials, but i have never thanks you.
once more your explanation is very helpful and even for non english speaker it's very easy to understand.

I hope you will continue like this !



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 25, 2012 at 7:26 PM
Experimenting With RESTful Error Response Codes And CFThrow's ErrorCode Attribute
Thanks Ben, That makes it much clearer. I must admit I misunderstood what you were trying to say about the api regarding using cfthrow. I particularly like the idea of custom error codes. I have som ... read »
May 25, 2012 at 6:39 PM
Experimenting With RESTful Error Response Codes And CFThrow's ErrorCode Attribute
@Ben, @Edward This is just an idea, some articles of RESTful I read says that... But definitely I'm agree to mantain the JSON body apart of the API framework... :) Can you share some RESTful artic ... read »
May 25, 2012 at 3:01 PM
Hashing Byte Arrays (Binary Data) With ColdFusion Before ColdFusion 10
Hello Ben and all. I tried ucase( digestUtils.sha512( imageBinary ) ) for SHA-512 hashing I get that dreaded: The sha512 method was not found. Either there are no methods with the specified ... read »
May 25, 2012 at 1:50 PM
Experimenting With RESTful Error Response Codes And CFThrow's ErrorCode Attribute
@Joaquin ... Not to nitpick but isn't kv statuscode a flag? ... read »
May 25, 2012 at 1:44 PM
ColdFusion 8 Application Specific Mappings Work With The CFComponent Extends Attribute
Yet another gotcha ... Always use forward slashes instead of backslashes ... it will pay off if you have to migrate your site from Windoze ... :-) ... read »
May 25, 2012 at 11:57 AM
Experimenting With RESTful Error Response Codes And CFThrow's ErrorCode Attribute
@Joaquin, Hmm, I could definitely see that. I like the idea of there being some sort of always-accessible value that is consistent. If nothing else, it can make code easier to write for the API con ... read »
May 25, 2012 at 10:57 AM
Experimenting With RESTful Error Response Codes And CFThrow's ErrorCode Attribute
Excellent Ben, I liked the article :) Just a tip (I think) is a best practice to add a status flag in the response even if all was good: JSON: { id: 5820, name: 'Sarah', age: 37, st ... read »
May 24, 2012 at 1:47 PM
ColdFusion Method Attribute Output=True Does Not Jive With EnableCFOutputOnly
The word 'jive' in your heading is, I think, in error. The word you wanted was 'gibe'. Of course, its five years later now, but what is that when your words will be immortal? ... read »