Wednesday, March 13, 2013

Exploring jQuery Queues

This week I ran into an interesting issue at work. There was an event that was triggered when a custom font loaded that added a fixed position element to an item in a container. Another team wrote some code that caused that container to animate when the page loaded. Sometimes the fixed position element would get placed randomly inside that container because the event was firing before the animation completed. Instead of tightly coupling the animation with the positioning of the element I decided to inspect the animating element's FX queue when the event was triggered to make sure that the element was not in the process of moving when it was added.
Queues in jQuery are a useful way to add a list functions to an element that should be executed in a particular order. The real benefit is that queues give you full control of when each item in the queue is invoked using the dequeue method. If you've used a jQuery animation function you've already used the jQuery fx queue. What a lot of people don't know is that jQuery provides a nice API for inspecting and manipulating queues.

Lets take a look at the typical use case for a jQuery queue; adding multiple animations to an element:



Demo:

JS Bin


When this code is executed each function is invoked one immediately right after the other. However, each animation is NOT performed instantly, each animation is added to the elements fx queue. When each animation is finished the next animation in the queue is invoked.

One interesting thing to note about the fx queue is that calling the stop() method on an element that is animating will only stop the current animation in the queue and immediately call the next animation in the queue. In order to truly stop all of the the animations the element's queue must be cleared as well.
In order to modify the first example to stop all animations when an element is clicked the following code is needed:



Demo:

JS Bin

Delaying And Creating Queues

Custom queues can be created on any elements by passing in a name to the queue call. In addition any queue's execution can be delayed when it is dequeued by using the delay( delayMs, queueName ) method. It's important to note that the delays are added to the queue itself so they need to be added to the queue before the function that you want delayed, however calling dequeue will trigger the delay and invoke the next callback from the queue. This timer will not start until dequeue() is called on the element's queue.

In the following example the queue's execution will be delayed by 1 second, an item will be added to the element, the queue will be delayed by another half second, another item will be appended to the element, the queue is then delayed for another second, and finally another item will be added to the element. The first item in the queue will be invoked in the $.ready() function and each callback in the queue will dequeue the next item in the queue.



Demo:

JS Bin

What makes custom queues with delays an attractive alternative to setTimeout or setInterval is that each item in the queue can have a different delay time before it is invoked.
Fork me on GitHub