jQuery 3 - Function Queues
Written by Ian Elliot   
Monday, 30 January 2017
Article Index
jQuery 3 - Function Queues
The Async Problem
Chained Auto Queuing

Chained Auto Queuing

Manually queuing and dequeuing isn't difficult but it is a bit messy. Using the jQuery idiom of function chaining we can hide the details and still make everything work. This is how the animation functions and the default fx queue work. 

What we have to do to convert the three functions so that they automatically use a function queue is change them so that they add the asynchronous part to the queue and remember to call next to move the queue on. This part is fairly easy. The difficult part is that we need an extra dequeue command to get things moving. It is difficult because you only want to do this when the first function is added to the queue. After that you can rely on the functions themselves to call next to move the queue on. Of course if the functions all finish then the queue becomes empty and the next time a function is added you once again need the extra dequeue command. 

The default queue keeps track of when the queue is active by placing a string at the start of the queue to act as a signal. We can't make us of this exact method for a general queue without modifying the inner workings of jQuery. Instead we can add a null function to the end of the queue to act as a state indicator. The idea is what when you are adding a function to an empty queue you know that it isn't active - i.e. there are no functions still active that might call next to move the queue on. This works as long as you follow the rule that every function you put on the queue calls next. If you put n functions on the queue then you need an explicit dequeue for the first but the subsequent functions are all dequeued by the previous function calling next. The final function will dequeue the null function leaving the queue empty and this is the signal that the queue is inactive.

The first thing we have to do is test to see if the queue is active. To do this we simply pop the last item off the queue. If the queue is empty then there is no last item and state is undefined. If the queue is active then there is a null function at the end and it needs to be removed to add the new function:

myF1: function () {
 var state = this.queue("myQ").pop();

With the null function removed we can add the function we actually want to place on the queue:

 this.queue("myQ", function (next) {
      setTimeout(function () {
        console.log("myF1");
        next();
      }, 3000); });

This is just the usual print a message to the console function complete with a call to next to move the queue on. 

Now we have to add the null function to the end of the queue:

this.queue("myQ", function () {});

This marks the queue as active but if it was inactive when we started adding a function to it we need to dequeue the function to get things going:

if (state === undefined)  this.dequeue("myQ");

Finally we return this so that the functions can be chained:

 return this;
}

 

Making the same modification each of the other functions means we can now call them using:

$({}).myF1().myF2().myF3();

and you will see myF1 printed in the log after 3 seconds followed by myF2 and myF3 after a further 2 and 1 seconds respectively. That is, the chaining automatically implements the queue to keep the asynchronous functions in the correct order. 

This might seem complicated but the only complication is due to the need to get the queue started with an extra dequeue operations. If you want to keep things simple you could manually include a dequeue.

The complete listing is:

$.fn.extend({
 myF1: function () {
        var state = this.queue("myQ").pop();
        this.queue("myQ", function (next) {
            setTimeout(function () {
              console.log("myF1");
              next();
            }, 3000);
        });
        this.queue("myQ", function () {});
        if (state === undefined) {
            this.dequeue("myQ");
        }
        return this;
      },

 myF2: function () {
        var state = this.queue("myQ").pop();
        this.queue("myQ", function (next) {
            setTimeout(function () {
              console.log("myF2");
              next();
            }, 2000);
        });
        this.queue("myQ", function () {});
        if (state === undefined) {
            this.dequeue("myQ");
        }
        return this;
      },

 myF3: function () {
        var state = this.queue("myQ").pop();
        this.queue("myQ", function (next) {
            setTimeout(function () {
              console.log("myF3");
              next();
            }, 1000);
        });
        this.queue("myQ", function () {});
        if (state === undefined) {
            this.dequeue("myQ");
        }
        return this;
      },
});


$({}).myF1().myF2().myF3();

 

Queues or Promises

Function queues are a simple and direct way of implementing correctly chained asynchronous functions. Promises are more sophisticated but you can do the same job using the then method in a similar way to next.

The big advantage of a Promise is that it can more easily handle errors. Any failure in the chain of functions propagates and can be picked up by a single function designed to deal with the problem. 

Function queues don't have the same sophistication when it comes to errors but in many cases they don't need to. If each function in the queue checks for its own error conditions that often all that is required to handle an error is to clear the queue so that the following functions don't execute.

If this isn't a suitable error handling strategy then you will either have to implement something different or move to using Promises, a topic which is covered in the forthcoming Asynchronous Programming & Ajax with jQuery 3.

For the moment function queues are here to stay and even if you don't use them for your own custom queues you will encounter them as part of any animation functions you might use - and these are described in the next chapter. 

 

justjquery

 Available as a Book:

smallcoverjQuery

buy from Amazon

  1. Understanding jQuery
  2. Basic jQuery CSS Selectors
       Extract: The DOM
  3. More Selectors
       Extract: Basic Selectors
  4. The JQuery Object
  5. Filters 
  6. DOM Traversal Filters 
  7. Modifying DOM Objects
       Extract: Modifying The DOM 
  8. Creating Objects & Modifying The DOM Hierarchy
  9. Working With Data
       Extract: Data ***NEW!!!
  10. Forms 
  11. Function Queues
  12. Animation 
  13. jQuery UI
  14. jQuery UI Custom Control
  15. Easy Plugins 
  16. Testing With QUnit
  17. Epilog A Bonus Function

Also Available:

jquery2cover

buy from Amazon

 

Banner


JavaScript Jems - The Inheritance Tax

JavaScript should not be judged as if it was a poor version of the other popular languages - it isn't a Java or a C++ clone. It does things its own way.  In particular, it doesn't do inheritance  [ ... ]



JavaScript Jems - Objects Are Anonymous Singletons

JavaScript should not be judged as if it was a poor version of the other popular languages - it isn't a Java or a C++ clone. It does things its own way.  In particular, every object can be regard [ ... ]


Other Articles

To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.

raspberry pi books

 

Comments




or email your comment to: comments@i-programmer.info

Banner


JavaScript Jems - The Inheritance Tax

JavaScript should not be judged as if it was a poor version of the other popular languages - it isn't a Java or a C++ clone. It does things its own way.  In particular, it doesn't do inheritance  [ ... ]



JavaScript Jems - Objects Are Anonymous Singletons

JavaScript should not be judged as if it was a poor version of the other popular languages - it isn't a Java or a C++ clone. It does things its own way.  In particular, every object can be regard [ ... ]


Other Articles

 



Last Updated ( Monday, 30 January 2017 )