Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Rewrote queue article this resolves #77 #176

Closed
wants to merge 2 commits into from

7 participants

@bentonam
Collaborator

This article was dated and needed to be rewritten. I am interested to hear your thoughts on it.

@bobholt
Collaborator

I dig it.

Only comment is to make sure the code examples comply with jQuery Core Styles. I'm going through existing content to close #29, so we should make sure any new commits comply. (Double quotes, and some spacing issues were the things I saw here).

@rwaldron
Collaborator
@ajpiano
Collaborator

@gnarf37 This PR is meant to address issue #77, which is to consolidate the old queue/dequeue article with your stackoverflow post, which is currently in the learn site archive as well. Can you give a quick review here and see if this achieves that end acceptably?

Also @bentonam, can you push a commit removing the "uses_of_queue_and_dequeue.md" (@gnarf's post) as well as the entry from order.yml? Thanks.

@gnarf

although this makes sense, using next() (the first argument to queue callback) is arguably easier to understand/use

Owner

lol oops, I just read the second example, I would perhaps only include that, leave the use of .dequeue() for another demo where it is outside of the queue() ?

@gnarf

heh, as silly as it sounds,this is the first time I've EVER seen clearQueue() used... Usually you'd .stop( true ) to clear queue

@gnarf

.stop( true ) probably better because it will stop the animation and clear the queue as opposed to only clearing the queue.

@addyosmani
Collaborator

If you could resolve the merge conflicts while this is being reworked that would also ease landing this. Thanks :)

@addyosmani
Collaborator

Ping @bentonam

@gnarf
Owner

( stealing this issue to test something - sorry! )

@gnarf gnarf closed this
@gnarf gnarf reopened this
@addyosmani
Collaborator

@bentonam @gnarf37

Do you think we could wrap up the work on this PR in the new year so we can bring it in? :)

@ajpiano
Collaborator

I still think this is an improvement over the existing article. Is there really anything else remaining here or do you think the branch just needs to be cleaned up so it can merge cleanly @gnarf37 ?

@gnarf
Owner
@ajpiano
Collaborator

If you can sign our CLA, I can clean this up and get it merged, @bentonam. Actually, @bobholt, if you could sign the CLA as well, we should have one on file for you as you've already got a bunch of commits on this repo too!

@eddiemonge

"If you can sign our CLA, I can clean this up and get it merged, @bentonam. Actually, @bobholt, if you could sign the CLA as well, we should have one on file for you as you've already got a bunch of commits on this repo too!"

@gnarf
Owner

We've asked for a CLA and can't merge without it. Going to close this for now. @bentonam i'd really like to take this change in, but it needs a rebase and someone to look over it again. If you're willing could you please sign the CLA and take a look at it again?

@gnarf gnarf closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Oct 19, 2012
  1. @bentonam
Commits on Oct 20, 2012
  1. @bentonam
This page is out of date. Refresh to see the latest.
Showing with 303 additions and 45 deletions.
  1. +303 −45 page/effects/queue_and_dequeue_explained.md
View
348 page/effects/queue_and_dequeue_explained.md
@@ -1,64 +1,322 @@
---
-title: Queue & Dequeue Explained
-level: beginner
-source: http://jqueryfordesigners.com/api-queue-dequeue/
+title: Queue & Dequeue Explained
+level: intermediate
---
-When you use the animate and show, hide, slideUp, etc effect methods, you’re
-adding a job on to the fx queue.By default, using queue and passing a function,
-will add to the fx queue. So we’re creating our own bespoke animation step:
+Queues are the foundation for all animations in jQuery, they allow a series functions to be executed asynchronously on an element. Methods such as `.slideUp()`, `.slideDown()`, `.fadeIn()`, and `.fadeOut()` all use `.animate()`, which leverages *queues* to build up the series of steps that will transition one or more CSS values throughout the duration of the animation.
+
+We can pass a callback function to the `.animate()` method, that will execute once the animation has completed.
```
-$('.box').animate({
- height : 20
-}, 'slow')
-.queue(function () {
- $('#title').html("We're in the animation, baby!");
-});
+$("#box")
+ .animate({
+ top: "100px",
+ left: "100px"
+ }, 1000, function() { // callback for when the animation is complete
+ console.log("animation complete!");
+ });
```
-As I said though, these methods come in pairs, so anything you add using queue,
-you need to dequeue to allow the process to continue. In the code above, if I
-chained more animations on, until I call $(this).dequeue(), the subsequent
-animations wouldn’t run:
+###Queues as Callbacks
+
+Instead of passing a callback as an argument, we can add another function to the *queue* that will act as our callback. This will execute after all of the steps in the animation have completed.
```
-$('.box').animate({
- height : 20
-}, 'slow')
-.queue(function () {
- $('#title').html("We're in the animation, baby!");
- $(this).dequeue();
-})
-.animate({
- height: 150
-});
+$("#box")
+ .animate({
+ top: "100px",
+ left: "100px"
+ }, 1000)
+ .queue(function() { // callback for when the animation is complete
+ console.log("animation complete!");
+ });
+```
+
+Now, lets take a look at adding multiple callbacks to be executed once our animation has been completed.
+
+```
+$("#box")
+ .animate({
+ top: "100px",
+ left: "100px"
+ }, 1000)
+ .queue(function() {
+ console.log("first callback!");
+ })
+ .queue(function() { // this won't execute
+ console.log("second callback!");
+ });
+```
+
+If you ran this, you will notice that **'second callback!'** was not logged to the console. This is because we have to tell jQuery that we are finished with the current entry and we want to move onto the next entry. We do this by *dequeuing* the next entry, which we can do in one of two ways. The first way is by directly calling the `.dequeue()` method.
+
+```
+$("#box")
+ .animate({
+ top: "100px",
+ left: "100px"
+ }, 1000)
+ .queue(function() {
+ console.log("first callback!");
+ // proceed to the next entry
+ $(this).dequeue();
+ })
+ .queue(function() {
+ console.log("second callback!");
+ // always call dequeue() even if it is the last entry
+ $(this).dequeue();
+ });
```
-Keeping in mind that the animation won’t continue until we’ve explicitly called
-dequeue, we can easily create a pausing plugin, by adding a step in the queue
-that sets a timer and triggers after n milliseconds, at which time, it dequeues
-the element:
+The second means of *dequeuing* is to call the function that jQuery passes to our queue handler as an argument. This function will step down to the next entry in the queue by calling `.dequeue()` for us automatically.
```
-$.fn.pause = function (n) {
- return this.queue(function () {
- var el = this;
- setTimeout(function () {
- return $(el).dequeue();
- }, n);
+$("#box")
+ .animate({
+ top: "100px",
+ left: "100px"
+ }, 1000)
+ .queue(function( next ) { // assign named argument of "next"
+ console.log("first callback!");
+ // call next() (which calls dequeue)
+ next();
+ })
+ .queue(function( next ) {
+ console.log("second callback!");
+ // always call next() even if it is the last entry
+ next();
});
-};
+```
+
+###Delaying Animations
+Sometimes it may be necessary to delay the start of an animation for various reasons. Generally when we thinking of delaying something, `setTimeout()` comes to mind, which will work perfectly fine for delaying the start of an animation.
+
+```
+// create a timeout for 2000ms then execute our animation
+setTimeout(function() {
+ $("#box")
+ .animate({
+ top: "100px",
+ left: "100px"
+ }, 1000);
+}, 2000);
+```
+
+However, jQuery v1.4 introduced the `.delay()` method, which will delay the execution of next entry in the queue for a specified amount of time. Since we know that all animations are ran via *queues*, we can call the `.delay()` method before calling `.animate()` and achieve the samething as our `setTimeout()` did in the previous example.
-$('.box').animate({
- height : 20
- }, 'slow')
- .pause(1000) // 1000ms == 1 second
+```
+$("#box")
+ .delay(2000) // delay the queue for 2000ms
.animate({
- height: 150
+ top: "100px",
+ left: "100px"
+ }, 1000);
+```
+
+While `.delay()` is basically just a wrapper for `setTimeout()`, the main advantage is that it allows us to maintain our call chain.
+
+###Custom Queues
+Up to this point all of our animation and queue examples have been using the default queue name which is *fx*. Elements can have multiple queues attached to them, and we can give each of these queues a different name. We can specify a custom queue name as the first argument to the `.queue()` method.
+
+```
+$("#box")
+ .queue("steps", function( next ) {
+ console.log("step 1");
+ next();
+ })
+ .queue("steps", function( next ) {
+ console.log("step 2");
+ next();
+ })
+ .queue("steps", function( next ) {
+ console.log("step 3");
+ next();
+ })
+ .dequeue("steps"); // start our custom queue
+```
+
+Here we have built a custom queue named **steps** that has three entries in it. Notice that we have to call the `.dequeue()` method passing it the name of our custom queue to start the execution. This is because any queue except for the default *fx* queue, has to be manually kicked off by calling `.dequeue()` and passing it the name of the queue.
+
+Likewise, we can delay custom queues just like we did with animations and the default queues in the earlier examples. We do this by passing `.delay()` an additional parameter telling it the name of the custom queue to delay.
+
+```
+$("#box")
+ .delay(1000, "steps")
+ .queue("steps", function( next ) {
+ console.log("step 1");
+ next();
+ })
+ .delay(1000, "steps")
+ .queue("steps", function( next ) {
+ console.log("step 2");
+ next();
+ })
+ .delay(1000, "steps")
+ .queue("steps", function( next ) {
+ console.log("step 3");
+ next();
+ })
+ .dequeue("steps"); // start our custom queue
+```
+
+Since queues are just a set of ordered operations, our application may have some logic in place that needs to prevent the remaining queue entries from executing. We can do this by calling the `.clearQueue()` method, which will empty the queue and in this example will prevent steps 2 and 3 from executing.
+
+```
+$("#box")
+ .queue("steps", function( next ) {
+ console.log("step 1");
+ // some condition
+ if ( 1 === 1 ) {
+ $(this).clearQueue("steps");
+ }
+ next();
+ })
+ .queue("steps", function( next ) {
+ console.log("step 2");
+ next();
+ })
+ .queue("steps", function( next ) {
+ console.log("step 3");
+ next();
+ })
+ .dequeue("steps");
+```
+
+###hoverIntent Plugin
+There is a popular jQuery plugin called **hoverIntent**, that was inspired by the `.hover()` method which ships with jQuery. It aims to determine a users intent when hovering over an element by delaying the firing of *mouseenter* event for a specified amount of time.
+
+```
+$("#box").hoverIntent(
+ function( event ) {
+ $(this).animate({
+ height: "+=50px"
+ }, 500);
+ },
+ function( event ) {
+ $(this).animate({
+ height: "50px"
+ }, 500);
+ }
+);
+```
+
+Now that we understand how to use `.delay()` and `.clearQueue()`, we can mimic the functionality of the **hoverIntent** plugin with just a few lines of code.
+
+```
+$("#box").hover(
+ function( event ) {
+ $(this)
+ .delay(200)
+ .animate({
+ height: "+=50px"
+ }, 500);
+ },
+ function( event ) {
+ $(this)
+ .clearQueue()
+ .animate({
+ height: "50px"
+ }, 500);
+ }
+);
+```
+
+For the *mouseenter* event we delay the animation by 200ms, then animate our element to whatever it's current height is plus 50px. For the *mouseleave* event, we clear the remaining entries in the queue and animate our element back to 50px. Now when the users mouse enters our element we will delay the start of the animation by 200ms, if the users mouse leaves our element before 200ms we will have removed the animation from the *fx* queue.
+
+###Working with Queues
+When creating queues we are not just limited to attaching them to a DOM element, we can also attach them to any jQuery object, in this case an empty object.
+
+```
+$({})
+ .queue("steps", function( next ) {
+ console.log("step 1");
+ next();
+ })
+ .queue("steps", function( next ) {
+ console.log("step 2");
+ next();
+ })
+ .dequeue("steps");
+```
+
+Building on the idea of attaching queues to an empty object, we can setup up a series of actions and then use an event to trigger the queue to start at a later time.
+
+```
+$theQueue = $({});
+// build up a queue but don't dequeue it
+$theQueue
+ .queue("steps", function( next ) {
+ console.log("step 1");
+ next();
+ })
+ .queue("steps", function( next ) {
+ console.log("step 2");
+ next();
+ });
+// bind a click event that will dequeue steps
+$("#go").on("click", function(event) {
+ $theQueue.dequeue("steps");
+});
+```
+
+###Queues and Arrays
+The easiest way to understand queues is to think of them as an array of functions, because that is exactly what they are.
+
+```
+$("#box")
+ .queue("steps", function( next ) {
+ console.log("step 1");
+ next();
+ })
+ .queue("steps", function( next ) {
+ console.log("step 2");
+ next();
+ })
+ .queue("steps", function( next ) {
+ console.log("step 3");
+ next();
});
+
+// calling console.log will give us [function(), function(), function()]
+console.log( $("#box").queue("steps") );
+```
+
+Since queues are arrays, we can manipulate them just as we would any other array as well as pass the `.queue()` method an array.
+
+```
+// setup the initial steps
+theSteps = [
+ function( next ) {
+ console.log("step 1");
+ next();
+ },
+ function( next ) {
+ console.log("step 2");
+ next();
+ }
+];
+
+// add the initial steps to the queue
+$("#box").queue("steps", theSteps);
+
+// get the queue
+theQueue = $("#box").queue("steps");
+
+// prepend a step to the queue
+theQueue.unshift(function( next ) {
+ console.log("beginning of the queue");
+ next();
+});
+
+// append a step to the queue
+theQueue.push(function( next ) {
+ console.log("end of the queue");
+ next();
+});
+
+// run the queue
+$("#box").dequeue("steps");
```
-Remember that the first argument for queue and dequeue are `fx`, and that in
-all of these examples I’m not including it because jQuery set the argument to
-`fx` by default - so I don’t have to specify it.
+###Summary
+Queues are extremely powerful, as we have seen they are the driving force for behind all of the animations in jQuery. We can leverage custom queues along with jQuery animations, to build a complex series of actions and execute it asynchronously in an ordered manner.
Something went wrong with that request. Please try again.