Simplifiez vos développements JavaScript avec jQuery
Last updated on Friday, December 6, 2013
  • Moyen

Free online content available in this course.

Paperback available in this course

eBook available in this course.

Got it!

Files d'attente et timer

Ce chapitre poursuit votre formation sur les animations. Vous y découvrirez entre autres comment enchaîner vos animations, ou au contraire comment les exécuter simultanément, comment répéter sans fin une animation, et comment mettre en place un timer pour exécuter du code à intervalles réguliers.

Les files d'attente jQuery

Les animations jQuery sont asynchrones, c'est-à-dire qu'elles s'exécutent en tâche de fond. Si vous enchaînez deux animations en utilisant une instruction du type suivant :

$('sel').animate(…).animate(…);

… alors la deuxième animation commence quand la première est terminée. Il s'agit là du comportement par défaut de jQuery : les animations sont placées dans une file d'attente et s'enchaînent, les unes à la suite des autres. Si vous souhaitez que plusieurs animations s'exécutent en même temps, il suffit d'indiquer les propriétés CSS à modifier dans le premier argument de la méthode animate() :

$('sel').animate({ prop1: val1, prop2: val2, } …);

Mais, dans ce cas, la vitesse d'exécution de chaque animation est commune. Si vous voulez exécuter plusieurs animations en même temps, chacune ayant une vitesse d'exécution qui lui est propre, vous devez utiliser une technique particulière, basée sur l'utilisation de la propriété queue dans la deuxième syntaxe de la méthode animate() :

$('sel').animate({ prop1: val1, prop2: val2, prop3: val3, etc. }, {queue: …});

Voyons tout cela en raisonnant sur un exemple pratique. Nous allons appliquer deux animations à une image : la première augmentera progressivement la largeur de la bordure et la deuxième diminuera progressivement la taille de l'image. Voici le code utilisé :

<button id="enchainer">Enchaîner les animations</button>
<button id="nePasEnchainer">Ne pas enchaîner les animations</button><br />
<button id="executerEnMemeTemps">Exécuter les animations en même temps</button>
<button id="etatInitial">État initial</button><br /><br />
<img src="logo.png" style="border: 2px black solid;">

<script src="jquery.js"></script>
<script>
  $(function() {
    $('#enchainer').click( function() {
      $('img').animate({ 'border-width': '100'}, 1500 )
              .animate({ 'width': '-=100'}, 1500);
    });  
    $('#nePasEnchainer').click( function() {
      $('img').animate({ 'border-width': '100'}, { queue: false, duration: 1500 })
              .animate({ 'width': '-=100'}, 1500);
    }); 
    $('#executerEnMemeTemps').click( function() {
      $('img').animate({ 'border-width': '100', 'width': '-=100' }, 1500);
    }); 
    $('#etatInitial').click( function() {
      $('img').css({'border-width': '2px', width: '200'});
    });  
  });
</script>

Essayer

Le corps du document définit quatre boutons ainsi qu'une image dont la bordure est définie par un style CSS.

Lorsque le premier bouton est cliqué par l'utilisateur, la bordure de l'image s'agrandit jusqu'à 100 pixels en 1500 millisecondes :

$('img').animate({ 'border-width': '100'}, 1500 )

Une fois cette première animation terminée, la largeur de l'image diminue de 100 pixels en 1500 millisecondes :

.animate({ 'width': '-=100'}, 1500);

Affichez cette page dans un navigateur et cliquez sur le premier bouton. Comme vous pouvez le voir, la bordure de l'image est modifiée, puis l'image est redimensionnée.

Lorsque le deuxième bouton est cliqué, la bordure de l'image s'agrandit jusqu'à 100 pixels en 1500 millisecondes. Comme la propriété queue est initialisée à false, la deuxième animation est exécutée en même temps que la première. Étant donné que les deux animations ont la même durée, elles s'exécuteront exactement en même temps :

$('img').animate({ 'border-width': '100'}, { queue: false, duration: 1500 })
        .animate({ 'width': '-=100'}, 1500);

Affichez cette page dans un navigateur et cliquez sur le deuxième bouton. La modification de la bordure et le redimensionnement de l'image se font en parallèle.

Lorsque le troisième bouton est cliqué, les deux animations sont exécutées en parallèle :

$('img').animate({ 'border-width': '100', 'width': '-=100' }, 1500);

Affichez cette page dans un navigateur et essayez de trouver une différence entre les animations associées au deuxième et au troisième bouton… Vous avez du mal à les différencier ? Cela est tout à fait normal, puisqu'elles produisent le même effet.

Mais alors, pourquoi utiliser le code du deuxième bouton ? Il est bien plus complexe et il produit le même effet !

Vous avez raison, à un détail près : si les deux traitements produisent le même effet, c'est parce que les deux animations ont une durée identique. Essayez de modifier la valeur affectée à la propriété duration, dans la méthode $('#nePasEnchainer').click(). Affectez-lui par exemple la valeur 500 et visualisez le résultat. Affectez maintenant la valeur 3000 à cette propriété et visualisez le résultat. Je suis sûr que maintenant vous comprenez l'intérêt du code attaché au deuxième bouton. ;)

Lorsque le quatrième bouton est cliqué, les propriétés CSS border-width et width de l'image sont initialisées à leurs valeurs originales, ce qui permet de retrouver l'image telle qu'elle était affichée à l'ouverture de la page :

$('img').css({'border-width': '2px', width: '200'});

État de la file d'attente

Quand plusieurs animations s'enchaînent sur un même objet, elles sont placées dans une file d'attente, prêtes à s'exécuter les unes après les autres. Pour connaître l'état de la file d'attente pour un objet particulier, vous lui appliquerez la méthode queue() sans aucun argument. Par exemple, pour connaître l'état de la file d'attente pour un élément d'identifiant #monElement, vous utiliserez cette instruction :

var resultat = $('#monElement').queue();

La méthode queue() retourne un tableau. Le nombre d'animations en attente d'exécution est égal au nombre d'éléments du tableau, et donc à resultat.length.

Pour illustrer cette méthode, nous allons nous appuyer sur quelques lignes de code jQuery. Nous allons appliquer une ou plusieurs animations à une image et tester le nombre d'animations en attente d'exécution en cliquant sur un bouton. Voici le code utilisé :

<button id="droite">Droite</button>
<button id="gauche">Gauche</button>
<button id="bas">Bas</button>
<button id="haut">Haut</button>
<button id="etatFile">Etat de la file d'attente</button><br />
<span id="infos">Cliquez sur Etat de la file d'attente</span><br /><br />
<img src="logo.png" style="position: relative;">

<script src="jquery.js"></script>
<script>
  $(function() {
    $('#droite').click( function() {
      $('img').animate({left: '+=50'}, 2000);
    });  
    $('#gauche').click( function() {
      $('img').animate({left: '-=50'}, 2000);
    });  
    $('#bas').click( function() {
      $('img').animate({top: '+=50'}, 2000);
    });  
    $('#haut').click( function() {
      $('img').animate({top: '-=50'}, 2000);
    });  
    $('#etatFile').click(function() {
      var n = $('img').queue();
      $('#infos').text('Nombre d\'animations dans la file d\'attente : ' + n.length);
    });  
  });
</script>

Essayer

Le document contient cinq boutons, une balise <span> et une image positionnée en relatif dans la page de façon à pouvoir être déplacée facilement. Très classiques, les quatre premiers boutons appliquent une animation de 2 secondes à l'image en la déplaçant respectivement vers la droite, vers la gauche, vers le bas et vers le haut. Par exemple, lorsque le bouton #haut est cliqué, le code suivant s'exécute :

$('img').animate({top: '-=50'}, 2000);

Lorsque le cinquième bouton est cliqué, la méthode queue() est appelée afin de connaître le nombre d'animations dans la file d'attente. L'objet retourné par la méthode queue() est stocké dans la variable n :

var n = $('img').queue();

En appliquant la fonction JavaScript length à cette variable, on obtient le nombre d'animations en attente d'exécution. Cette information est affichée dans la balise <span>#infos :

$('#infos').text('Nombre d\'animations dans la file d\'attente : ' + n.length);

Manipuler la file d'attente

Dans les sections précédentes, vous avez appris à utiliser la propriété queue pour indiquer si une animation devait ou ne devait pas être placée dans la file d'attente, et la méthode queue() pour connaître l'état de la file d'attente. Vous allez maintenant apprendre à utiliser les méthodes queue(), dequeue() et clearQueue() pour manipuler la file d'attente :

  • queue() ajoute une animation dans la file d'attente ;

  • dequeue() joue puis supprime une animation de la file d'attente ;

  • clearQueue() vide la file d'attente.

Comme toujours, c'est par la pratique que vous allez comprendre le fonctionnement de ces méthodes. Dans cet exemple, deux images sont affichées dans le navigateur. À l'aide de quatre boutons de commande, vous allez pouvoir :

  • Jouer une animation, puis, lorsqu'elle sera terminée, ajouter d'autres animations dans la file d'attente avec la méthode queue() ;

  • Supprimer le contenu de la file d'attente ;

  • Remplacer le contenu de la file d'attente ;

  • Ajouter une fonction de retour à la file d'attente.

Voici le code utilisé :

<button id="ajouter">Ajouter animation</button>
<button id="annuler">Annuler la file d'attente</button><br />
<button id="remplacer">Remplacer la file d'attente</button>
<button id="retour">Ajouter une fonction de retour</button><br />
<img src="bon.gif" id="bon" style="position: relative;">
<img src="mauvais.gif" id="mauvais" style="position: relative;">

<script src="jquery.js"></script>
<script>
  $(function() {
    $('#ajouter').click( function() {
      $('#bon').toggle(5000)
               .queue(function() { 
                 $('#mauvais').animate({left: '+=200'}, 'slow')
                 .animate({top: '+=200'}, 'slow')
                 .animate({left: '-=200'}, 'slow')
                 .animate({top: '-=200'}, 'slow');
               });
    });  
    $('#annuler').click( function() {
        $('img').clearQueue();
    });  
    $('#remplacer').click( function() {
      $('#mauvais').css('left', 200).css('top', 200);
      $('#mauvais').queue(function() {
                   $(this).animate({top: '-=200'}, 'slow')
                          .animate({top: '+=200', 'left': '-=200'}, 'slow')
                          .animate({top: '-=200'}, 'slow');
                   $(this).dequeue();
                   });
    });  
    $('#retour').click( function() {
      $('img').queue(function() {
            alert('Animation terminée.');
            $(this).dequeue();
       });
    });  
  });
</script>

Lorsque le premier bouton (#ajouter) est cliqué, la méthode toggle est appliquée à l'image d'identifiant #bon pour la faire disparaître ou apparaître, selon qu'elle soit visible ou non :

$('#bon').toggle(5000)

Lorsque cette première animation est terminée (c'est-à-dire au bout de 5 secondes), quatre autres animations sont placées dans la file d'attente à l'aide de la méthode queue() :

.queue(function() { 
  $('#mauvais').animate({left: '+=200'}, 'slow')
  .animate({top: '+=200'}, 'slow')
  .animate({left: '-=200'}, 'slow')
  .animate({top: '-=200'}, 'slow');
   });
});

Le code associé au deuxième bouton de commande est simplissime : il se contente d'appeler la méthode clearQueue() pour effacer le contenu de la file d'attente :

$('#annuler').click( function() {
  $('img').clearQueue();
});

Lorsque le troisième bouton est cliqué, la méthode css() est invoquée à deux reprises pour déplacer l'image #mauvais en (200, 200) :

$('#mauvais').css('left', 200).css('top', 200);

Une animation sur l'image #mauvais est placée dans la file d'attente :

$('#mauvais').queue(function() {
  $(this).animate({top: '-=200'}, 'slow')
         .animate({top: '+=200', 'left': '-=200'}, 'slow')
         .animate({top: '-=200'}, 'slow');

En invoquant la méthode dequeue(), cette animation est jouée immédiatement et enlevée de la file d'attente :

$(this).dequeue();

Enfin, lorsque le quatrième bouton est cliqué, une fonction de retour est ajoutée à la file d'attente via la méthode queue(). Cette fonction se contente d'afficher une boîte de message pour indiquer que l'animation est terminée :

$('img').queue(function() {
      alert('Animation terminée.');
      $(this).dequeue();
 });

Répéter une animation sans fin

Toutes les animations jQuery présentées jusqu'ici s'exécutaient suite à des actions de l'utilisateur et s'arrêtaient après leur exécution. Que diriez-vous d'exécuter une animation en boucle ?

Le principe repose sur la définition d'une fonction JavaScript dans laquelle on insère un ou plusieurs appels à la méthode animate(). Le dernier de ces appels utilise une fonction de rappel qui exécute… cette même fonction JavaScript !

Pour illustrer mes propos, nous allons déplacer indéfiniment une balise <div> sur un carré de 200 pixels de côté. Voici le code utilisé :

<style type="text/css">
  #balle {
    width: 10px;
    height: 10px;
    background-color: red;
    border: black 2px solid;
    border-radius: 10px;
    position: relative;
  }
</style>

<div id="balle"></div>

<script src="jquery.js"></script>
<script>
  $(function() {
    function bis() {
      $('#balle').animate({left: '+=200'}, 'slow')
                 .animate({top: '+=200'}, 'slow')
                 .animate({left: '-=200'}, 'slow')
                 .animate({top: '-=200'}, 'slow', bis);
    };
    bis();
  });
</script>

Essayer

Le corps du document contient une simple balise <div> d'identifiant #balle. Cette balise est mise en forme par quelques instructions CSS. Sont ainsi définies les dimensions, la couleur d'arrière-plan, la bordure et le type de positionnement.

La fonction bis() décrit un cycle d'animation de la balise <div>. Elle est tout d'abord déplacée vers la droite de 200 pixels en 200 millisecondes, puis vers le bas de 200 pixels en 200 millisecondes, puis vers la gauche de 200 pixels en 200 millisecondes et enfin vers le haut de 200 pixels, toujours en 200 millisecondes :

$('#balle').animate({left: '+=200'}, 'slow')
           .animate({top: '+=200'}, 'slow')
           .animate({left: '-=200'}, 'slow')
           .animate({top: '-=200'}, 'slow', bis);
};

Remarquez le dernier paramètre de la méthode animate(). En utilisant la fonction de rappel bis(), un nouveau cycle d'animation est lancé.

Arrêter et reprendre une animation

La méthode stop() permet d'arrêter une animation. Selon les paramètres qui lui sont passés, cette méthode peut supprimer ou non les animations en attente et/ou afficher l'état final de l'animation. Voici sa syntaxe :

$('sel').stop(efface, fin);

… où :

  • sel est un sélecteur jQuery ;

  • efface est une valeur booléenne qui indique si les animations en attente d'exécution doivent être (true) ou non (false) supprimées de la file d'attente ;

  • fin est une valeur booléenne qui indique si l'animation doit prendre son état final (true) ou non (false). Si ce paramètre n'est pas spécifié, l'animation reste dans l'état où elle se trouvait au moment de son arrêt.

Dans l'exemple suivant, deux animations sont appliquées à une image : un décalage vers la droite, puis un décalage vers le bas. À tout moment, l'utilisateur peut arrêter l'animation en cours en cliquant sur un bouton de commande. Trois types d'arrêt sont proposés :

  • Arrêt et positionnement à la fin de l'animation en cours ;

  • Arrêt de l'animation en cours, annulation des animations en attente et déplacement à la fin de l'animation en cours ;

  • Simple arrêt de l'animation.

Un autre bouton permet de reprendre l'animation comme à l'ouverture de la page. Voici le code utilisé :

<button id="stopFin">Stop et fin</button>
<button id="stopAnnuleFin">Stop, annule et fin</button>
<button id="stop">Stop</button>
<button id="reprise">Reprise</button><br /><br />
<img src="image.png" style="position: relative;">

<script src="jquery.js"></script>
<script>
  $(function() {
    $('img').animate({left: '+=500'}, 2000).animate({top: '+=300'}, 2000);
    $('#stopFin').click( function() {
      $('img').stop(false, true);
    });  
    $('#stopAnnuleFin').click( function() {
      $('img').stop(true, true);
    });  
    $('#stop').click( function() {
      $('img').stop(true, false);
    });  
    $('#reprise').click( function() {
      $('img').css('left', 0).css('top', 0);
      $('img').animate({left: '+=500'}, 2000).animate({top: '+=300'}, 2000);
    });  
  });
</script>

Dès que le DOM est prêt, l'image est animée :

$(function() {
    $('img').animate({left: '+=500'}, 2000).animate({top: '+=300'}, 2000);

L'utilisateur peut alors cliquer sur l'un des trois premiers boutons pour arrêter l'animation. Un clic sur le premier bouton met fin à l'animation en cours, ne supprime pas les animations dans la file d'attente (premier paramètre false) et place l'image dans sa position finale (deuxième paramètre true) :

$('#stopFin').click( function() {
  $('img').stop(false, true);
});

Un clic sur le deuxième bouton met fin à l'animation en cours, supprime les animations dans la file d'attente (premier paramètre true) et place l'image dans sa position finale (deuxième paramètre true) :

$('#stopAnnuleFin').click( function() {
  $('img').stop(true, true);
});

Enfin, un clic sur le troisième bouton met fin à l'animation en cours, supprime les animations dans la file d'attente (premier paramètre true) et laisse l'image dans sa position actuelle (deuxième paramètre false) :

$('#stop').click( function() {
  $('img').stop(true, false);
});

Examinons la dernière méthode événementielle. Lorsque l'utilisateur clique sur le quatrième bouton, l'image est repositionnée à son emplacement d'origine :

$('img').css('left', 0).css('top', 0);

… et l'animation qui lui a été appliquée à l'ouverture de la page est relancée :

$('img').animate({left: '+=500'}, 2000).animate({top: '+=300'}, 2000);

Mettre en place un timer

Vous avez vu dans ce chapitre qu'il était possible de répéter une série d'animations en plaçant toutes les animations dans une fonction, et en utilisant la fonction de rappel de la dernière animation pour exécuter à nouveau la fonction. Une autre technique est possible. Je tenais à vous la montrer avant de terminer ce chapitre, car elle vous sera certainement utile si vous vous aventurez à créer des jeux ou des zones animées sur le Web. Cette technique consiste à utiliser un timer JavaScript via la fonction setInterval() :

function nom() {
  // Une ou plusieurs instructions JavaScript et/ou jQuery
}
setInterval(nom, période);

… où :

  • nom est le nom de la fonction qui doit être exécutée périodiquement ;

  • durée est la période (c'est-à-dire le temps) entre deux exécutions consécutives des instructions contenues dans la fonction.

Une horloge élémentaire

Dans ce premier exemple, nous allons réaliser une horloge numérique élémentaire en utilisant la fonction JavaScript setInterval(). L'heure sera mise à jour toutes les secondes dans une balise <span> en utilisant une instruction jQuery. Voici le code utilisé :

<span id="heure"></span>

<script src="jquery.js"></script>
<script>
$(function() {
  function Horloge() {
    var laDate = new Date();
    var h = laDate.getHours() + ":" + laDate.getMinutes() + ":" + laDate.getSeconds();
    $('#heure').text(h);
  }
  setInterval(Horloge, 1000);
});
</script>

Lorsque le DOM est disponible, la fonction Horloge() est définie. Après avoir créé l'objet Date, les heures, minutes et secondes sont récupérées via les fonctions getHours(), getMinutes() et getSeconds(), et stockées dans la variable h :

function Horloge() {
  var laDate = new Date();
  var h = laDate.getHours() + ":" + laDate.getMinutes() + ":" + laDate.getSeconds();

Le contenu de la balise <span>#heure est alors mis à jour en y affichant la valeur qui vient d'être stockée dans la variable h :

$('#heure').text(h);

Pour que la fonction Horloge() s'exécute toutes les secondes, il suffit maintenant d'utiliser la fonction setInterval() en passant Horloge en premier argument et 1000 en deuxième argument :

setInterval(Horloge, 1000);

Une animation sans fin

Ce deuxième exemple reprend l'animation de la section « Répéter une animation sans fin » et l'exécute en boucle avec la fonction setInterval(). Voici le code utilisé :

<!DOCTYPE html>
<style type="text/css">
  #balle {
    width: 10px;
    height: 10px;
    background-color: red;
    border: black 2px solid;
    border-radius : 10px;
    position: relative;
  }
</style>

<body>
  <div id="balle"></div>
  <script src="jquery.js"></script>
  <script>
    $(function() {
      function bis() {
        $('#balle').animate({left: '+=200'}, 'slow')
                   .animate({top: '+=200'}, 'slow')
                   .animate({left: '-=200'}, 'slow')
                   .animate({top: '-=200'}, 'slow');
      };
      setInterval(bis, 2400);
    });
  </script>

Le corps du document ne contient qu'une balise <div> d'identifiant #balle. Lorsque le DOM est disponible, la fonction JavaScript bis() est définie. Dans cette fonction se trouvent les quatre animations qui font décrire un carré à la balle :

function bis() {
  $('#balle').animate({left: '+=200'}, 'slow')
             .animate({top: '+=200'}, 'slow')
             .animate({left: '-=200'}, 'slow')
             .animate({top: '-=200'}, 'slow');
};

Si vous pensez qu'il n'y a rien de bien nouveau dans ce code, examinez la dernière méthode animate() : la fonction de rappel a disparu !

Cela est tout à fait normal puisque l'exécution répétée de la fonction bis() ne va pas se faire par la fonction de rappel de la dernière animation, mais par une instruction setInterval(). Cette instruction suit la fonction bis(). Elle appelle la fonction bis() toutes les 2400 millisecondes :

setInterval(bis, 2400);

Pourquoi avoir choisi 2400 millisecondes ?

Réfléchissez un peu… La valeur slow, passée en deuxième argument des quatre méthodes animate, correspond à une durée de 600 millisecondes. Étant donné que l'on enchaîne quatre animations, vous avez votre réponse. :p

  • Les animations jQuery sont asynchrones. Si vous lancez plusieurs animations, elles seront placées dans une file d'attente. La énième animation ne pourra être lancée que lorsque la précédente sera terminée… à moins que vous n'agissiez sur la file d'attente. Pour cela, vous utiliserez la deuxième syntaxe de la méthode animate() pour déclencher simultanément plusieurs animations.

  • Pour connaître le nombre d'animations qui se trouvent dans la file d'attente, utilisez la méthode queue() sans argument et testez sa propriété length.

  • Vous pouvez utiliser les méthodes queue(), dequeue() et clearQueue() pour manipuler la file d'attente : queue() ajoute une animation dans la file d'attente, dequeue() joue puis supprime une animation de la file d'attente, clearQueue() vide la file d'attente.

  • La méthode stop() met fin à l'animation en cours. Selon les paramètres qui lui sont passés, les animations suivantes sont ou ne sont pas effacées de la file d'attente et l'animation est affichée dans son état final ou s'arrête simplement.

  • Deux techniques permettent de répéter une série d'animations sans fin. Après avoir inclus les animations dans une fonction, vous pouvez :

    • Utiliser la fonction de rappel de la dernière animation pour rappeler la fonction ;

    • Appeler la fonction en mettant en place un timer JavaScript.

Example of certificate of achievement
Example of certificate of achievement