jQuery: using timers with animations

JavaScript timers constitute the inner engine of any good automated jQuery slideshow. Although timers can be really handy in most situations and case-scenarios, their rules are somewhat obscure to many developers. The point is that timers can be used in a wide range of use cases, not only in animations. For that reason, you should understand how timers work when applied to jQuery animations before developing any practical implementation that makes use of them.

Delays: setTimeout()

The setTimeout() method is primarily used to create a delay between an action and the subsequent one or to prevent an action from being executed immediately:

function appear(element) {

 $(element).fadeIn(1000); 

}

setTimeout(function() {

 appear('#test');

}, 1000);

This is a wait-and-go action: the timer delays the execution of the function for one second (1,000 milliseconds) but the function itself uses an effect whose duration is of another second. Globally, the whole action takes 2 seconds to finish its task.

As a rule of thumb, you should always add up the duration of your animation to the overall duration of the timer you're using. By doing this, you have the exact duration of the entire action.

Delays can be applied on many scenarios. One of the most interesting examples is the animation chain created through deferred objects:

$.Deferred(function(def) {

 def.pipe(function() {
 
  return $('#a').animate({
   left: 100
  }, 1000);
 
 }).pipe(function() {
 
  return setTimeout(function() {
  
   $('#b').animate({
    left: 200
   }, 1000);
  
  }, 1000);
 
 });


}).resolve();

The second animation must wait until the first one is complete. Since the first animation has a duration of 1,000 milliseconds, then the timer must have a delay of exactly 1,000 milliseconds to create the effect of an animation chain where every animation follows the previous one. If you don't do so, both animations will start simultaneously.

Speaking of delays, another practical application can be found in the dropdown menu handling where you can prevent a submenu from disappearing too fast:

$('ul.sub-menu').mouseleave(function() {

    var $menu = $(this);

 setTimeout(function() {
 
  $menu.slideUp(800); 
 
 }, 500);

});

Intervals: setInterval()

setInterval() has exactly the same syntax as setTimeout(). The main difference between these two methods is that setInterval() creates a cyclic timer whose execution is virtually infinite if you don't stop it once it has reached a certain limit:

var timer = setInterval(function() {

 index++;
 
 if(index == limit) {
 
  index = 0;
 
 }

}, 1000);

In this case the inner counter is incremented by 1 every second. When the counter reaches its limit (say, 5), it will be reset to 0 so that the cycle can start again. And so on.

This method can be useful on automated slideshows:

var autoSlide = function() {

 timer = setInterval(function() {
 
  index++;
  
  if(index == slides.length) {
  
   index = 0;
  
  }
  
  var position = slides.eq(index).position().left;
  
  wrapper.animate({
   left: - position
  }, 1000);
 
 }, 1000);


};

Be careful with the duration of your animations within a timer: you should always make sure that the overall duration of your animations match the duration of the interval defined by the timer (in this case, 1 second for both the animation and the interval).

For that reason, setInterval() is not very practical when you have to deal with multiple animations, because you'll probably end up with an interval that is too long for your needs. Nicholas Zakas proposes the following alternate solution:

timer = setTimeout(function() {

 // various animations that last 5,000 milliseconds
 
 setTimeout(arguments.callee, 5000);

}, 1000);

The above timer will also repeat itself because of the second call to setTimeout() but with a significant difference: you have only to wait one second between each execution whereas setInterval() requires you to wait 5 seconds.

Clearing timers and animations

To clear the aforementioned methods you can use clearTimeout() and clearInterval(), respectively. Is that all? Unfortunately not, because you have also to clear the animation queue.

Consider this example: you have a jQuery slideshow which features both an autosliding effect and navigation buttons. When you click on a button, you should stop the automatic sliding effect:

$('#prev').click(function(event) {

 clearInterval(timer);
 timer = null;
 
 var position = slides.eq(index).position().left; // index belongs to the global namespace of your slideshow
 
 wrapper.animate({
  left: - position
 }, 1000, autoSlide);

 event.preventDefault();

});

Once the action bound to the button is complete, you can restart your timer. But this is not enough. In fact, if you click twice on that button, everything will fall apart. That's because the animation queue is still active. You have to reset it as well:

$('#prev').click(function(event) {

 clearInterval(timer);
 timer = null;
 $(':animated', slideshow).clearQueue();
 
 var position = slides.eq(index).position().left; // index belongs to the global namespace of your slideshow
 
 wrapper.animate({
  left: - position
 }, 1000, autoSlide);

 event.preventDefault();

});

By doing so, you've normalized everything so you can start with a clean slate again.

This entry was posted in by Gabriele Romanato. Bookmark the permalink.

One thought on “jQuery: using timers with animations”

  1. Hey you REALLY should look at delay and queue methods that are bundled on jQuery library already....

Leave a Reply

Note: Only a member of this blog may post a comment.