jQuery : Les bonnes pratiques

By | octobre 26, 2009 at 26 10 09 | 45 comments | Ressources

Parce que beaucoup de développeurs se frottant à jQuery ne l’utilise pas forcément comme il faut et se plaignent souvent des performances médiocres obtenues,  il était temps de remettre l’église au centre du village.

Ce mémo est une traduction de ce très bon article anglais.

Bonne lecture !

Toujours faire une recherche à partir d’un ID

Le sélecteur le plus rapide de jQuery est le sélecteur d’ID ($(‘#mon-id’)) car elle est directement mappée sur une méthode Javascript native : getElementById().

Sélection d’un élément unique

<div id="content">
 <form method="post" action="/">
  <h2>Traffic Light</h2>
   <ul id="traffic_light">
    <li><input type="radio" name="light" value="red" />Red</li>
    <li><input type="radio" name="light" value="yellow" />Yellow</li>
    <li><input type="radio" name="light" value="green" />Green</li>
   </ul>
   <input class="button" id="traffic_button" type="submit" value="Go" />
 </form>
</div>

Une sélection comme celle-ci est plus rapide :
var traffic_button = $(‘#traffic_button’);

Que celle-ci :
var traffic_button = $(‘#content .button’);


Sélection d’éléments multiples

La sélection d’éléments multiples parcours le DOM de manière transversale, cela peut être très long et très couteux en ressources.
Pour minimiser les pertes de performances, toujours effectuer une recherche à partir de l’ID du parent le plus proche :
var traffic_lights = $(‘#traffic_light input’);


Utiliser des balises avant les classes

Le second sélecteur le plus rapide de jQuery est le sélecteur de balises ($(‘head’)). Toujours parce qu’il s’agit d’un mappage vers une méthode native de JavaScript, getElementsByTagName().

<pre lang="html4strict" escaped="true"><div id="content">
 <form method="post" action="/">
  <h2>Traffic Light</h2>
   <ul id="traffic_light">
    <li><input type="radio" name="light" value="red" />Red</li>
    <li><input type="radio" name="light" value="yellow" />Yellow</li>
    <li><input type="radio" name="light" value="green" />Green</li>
   </ul>
   <input id="traffic_button" type="submit" value="Go" />
 </form>
</div>

Il faut donc toujours préfixer une classe par une balise (et se souvenir qu'il faut commencer par un ID) :
var active_light = $('#traffic_light input.on');
Note : Le sélecteur de classe est l'un des plus lents dans jQuery, sous Internet Explorer il boucle sur le DOM complet. Evitez de l'utiliser chaque fois que c'est possible.

Il ne faut jamais préfixer un ID par une balise. Cela ralenti le processus de recherche car jQuery va boucler sur tous les div à la recherche de l'ID 'content' :
var content = $('div#content');

De la même manière il est inutile est redondant de faire une recherche à partir de
plusieurs ID :
var traffic_light = $('#content #traffic_light');


Cacher les objets jQuery

Prenez l'habitude de sauver vos objets jQuery dans des variables (comme dans les exemples précédents).
Par exemple, il ne faut jamais faire cela :

$('#traffic_light input.on').bind('click', function(){...});
$('#traffic_light input.on').css('border', '3px dashed yellow');
$('#traffic_light input.on').css('background-color', 'orange');
$('#traffic_light input.on').fadeIn('slow');

Mais plutôt passer une variable locale avant de continuer vos traitements :

var $active_light = $('#traffic_light input.on');
$active_light.bind('click', function(){...});
$active_light.css('border', '3px dashed yellow');
$active_light.css('background-color', 'orange');
$active_light.fadeIn('slow');

Astuce : Pour se souvenir que notre variable contient un objet jQuery nous pouvons la préfixer avec un $.

Souvenez-vous : ne faite jamais deux fois la même sélection !!


Garder le résultat d'une sélection pour plus tard

Si vous prévoyez d'utiliser le résultat d'une sélection dans une autre partie de votre programme ou devez utiliser la même fonction plusieurs fois, cacher ce résultat dans une variable globale.
En définissant un conteneur global de résultats jQuery nous pouvons les utiliser depuis l'intérieur d'autres fonctions :

// Définissez un objet global (c.à.d. l'objet window)
 window.$my =
 {
 // Initialisez toutes les requêtes qui vont vous servir plus d'une fois.
 head : $('head'),
 traffic_light : $('#traffic_light'),
 traffic_button : $('#traffic_button')
 };
 
function do_something()
 {
 // maintenant vous pouvez utiliser les résultats stockés et les manipuler.
 var script = document.createElement('script');
 $my.head.append(script);
 
// Quand vous travaillez dans les fonctions, continuez de sauvegarder
 // vos résultats de requête jQuery dans votre conteneur global.
 $my.cool_results = $('#some_ul li');
 $my.other_results = $('#some_table td');
 
// Utilisez votre conteneur global comme un résultat de requête classique :
 $my.other_results.css('border-color', 'red');
 $my.traffic_light.css('border-color', 'green');
 }

(Dé)chaînez la fureur

L'exemple du précédent peut également être accompli de la façon suivante :

var $active_light = $('#traffic_light input.on');
$active_light.bind('click', function(){...})
 .css('border', '3px dashed yellow')
 .css('background-color', 'orange')
 .fadeIn('slow');

Cela permet d'écrire moins de code, rendant notre Javascript plus léger.

Utilisez des sous-requêtes

Par exemple, nous pouvons utiliser des sous-requêtes pour récupérer et cacher les champs actifs et inactifs de notre exemple :

<div id="content">
 <form method="post" action="/">
  <h2>Traffic Light</h2>
  <ul id="traffic_light">
   <li><input type="radio" name="light" value="red" />Red</li>
   <li><input type="radio" name="light" value="yellow" />Yellow</li>
   <li><input type="radio" name="light" value="green" />Green</li>
  </ul>
  <input id="traffic_button" type="submit" value="Go" />
 </form>
</div>
var $traffic_light = $('#traffic_light'),
 $active_light = $traffic_light.find('input.on'),
 $inactive_lights = $traffic_light.find('input.off');

Astuce : Vous pouvez déclarer plusieurs variables en les séparant avec des virgules – sauvez des octets !


Limiter les manipulations directes du DOM

L'idée de base ici est de créer exactement ce dont vous avez besoin en mémoire, et ensuite mettre à jour le DOM. Il ne s'agit pas que d'un conseil pour jQuery mais pour Javascript en général.

Par exemple, si vous avez besoins de créer dynamiquement une liste d'éléments,
ne faite pas ça :

var top_100_list = [...], // On suppose qu'il y a 100 strings différents
 $mylist = $('#mylist'); // jQuery sélectionne notre <ul>
 
 for (var i=0, l=top_100_list.length; i<l; i++)
 {
  $mylist.append('<li>' + top_100_list[i] + '</li>');
 }

A la place, nous allons d'abord créer la collection d'éléments dans une chaine avant de l'insérer au DOM :

var top_100_list = [...], // On suppose qu'il y a 100 strings différents
 $mylist = $('#mylist'), // jQuery sélectionne notre <ul>
 top_100_li = ""; // C'est ici qu'on va stocker notre liste
 for (var i=0, l=top_100_list.length; i<l; i++)
 {
  top_100_li += '<li>' + top_100_list[i] + '</li>';
 }
 $mylist.html(top_100_li);

Encore plus rapide, nous devrions toujours encapsuler plusieurs éléments dans une node parente avant l'insertion :

var top_100_list = [...], // On suppose qu'il y a 100 strings différents
 $mylist = $('#mylist'), // jQuery sélectionne notre <ul>
 top_100_ul = '<ul id="#mylist">'; // On stock toute notre liste
 
for (var i=0, l=top_100_list.length; i<l; i++)
 {
  top_100_ul += '<li>' + top_100_list[i] + '</li>';
 }
  top_100_ul += '</ul>'; // On ferme notre liste
 
$mylist.replaceWith(top_100_ul);

Exploiter la délégation d'événement

En Javascript, chaque événement est remonté aux éléments parents le long de l'arborescence du DOM.
C'est extrêmement pratique quand nous voulons que plusieurs éléments fils (nodes) appellent une même fonction.

Plutôt que d'associer une fonction de listener d'événements à plusieurs nodes (très peu efficace) vous pouvez l'associer une fois pour toute à leur parent, en le laissant se débrouiller avec l'élément fils qui a déclenché l'événement.

Par exemple, nous développons un gros formulaire avec beaucoup de champs, et nous voulons changer la classe d'un champ lorsque ce dernier est sélectionné.

Une association telle que celle-ci n'est pas du tout optimisée :

$('#entryform input).bind('focus', function(){
  $(this).addClass('selected');
}).bind('blur', function(){
  $(this).removeClass('selected');
});

A la place, nous devrions surveiller les événements de focus et de blur au niveau du parent :

$('#entryform).bind('focus', function(e){
 
var cell = $(e.target);      // e.target récupère l'élément qui a
 cell.addClass('selected');  // déclenché l'événement.
 
}).bind('blur', function(e){
 
var cell = $(e.target);
 cell.removeClass('selected');
 
});

L'élément parent agit comme un dispatcher et peut ainsi travailler sur l'élément fils cible qui a déclenché l'événement. Si vous associez un même listener à plusieurs éléments, faite attention, vous êtes en train de coder quelque chose de très lent !

Eliminez les requêtes superflues

Même si jQuery échoue proprement quand il ne trouve pas d'élément, cela ne veux pas dire qu'il ne perd pas de temps à les chercher !
Si vous avez un fichier Javascript global pour votre site, il est tentant d'exécuter toutes vos recherches dans

$(document).ready(function(){ // tout mon joli code })

C'est mal ! N'exécutez que les fonctions applicables à la page courante.
La façon la plus efficace de faire cela est d'utiliser des fonctions d'initialisation légère pour que votre template ait le contrôle complet sur où etquand est exécuter votre Javascript.

Par exemple, vous pouvez inclure le code suivant avant la fermeture de la balise body :

 <script type="text/javascript>
  mylib.article.init();
 </script>
</body>

Si votre template de page inclus une variété de modules qui peuvent être ou ne pas être dans la page, ou si pour d'autre raison vous avez besoins de les initialiser plus tôt vous pouvez placer la fonction d'initialisation immédiatement après le module.

<ul id="traffic_light">
 <li><input type="radio" name="light" value="red" /> Red</li>
 <li><input type="radio" name="light" value="yellow" /> Yellow</li>
 <li><input type="radio" name="light" value="green" /> Green</li>
 </ul>
 <script type="text/javascript>
 mylib.traffic_light.init();
 </script>

Votre bibliothèque javascript globale ressemblerait à ça :

var mylib =
{
  article_page :
  {
   init : function()
   {
   // Mes fonctions jQuery spécifiques à la page d'article.
   }
  },
  traffic_light :
  {
  init : function()
   {
   // Mes fonctions jQuery spécifiques à la page trafic.
   }
  }
}

Déléguez à $(window).load

Il y a une tentation parmi tous les développeurs jQuery à associer toutes leurs fonctions à l'événement $(document).ready.

Après tout, il est utilisé dans la plupart des exemples que vous trouverez sur le web, pourquoi changer ?
$(document).ready se déclenche pendant le rendering de la page par le navigateur, c'est-à-dire au même moment où des éléments sont encore téléchargé par ce dernier.

Si vous remarqué un ralentissement du navigateur durant le chargement de la page, toutes ces fonctions $(document).ready en sont peut-être la raison.

Vous pouvez réduire l'utilisation CPU en affectant toutes vos fonctions jQuery à l'événement $(window).load qui est déclenché après que tous les objets appelés par le HTML soit téléchargés. (Y compris le contenu des iframes).

$(window).load(function(){
 // Fonctions jQuery a initialiser après que la page ait été chargée.
 });

Les fonctionnalités "superflues" telles que les drap-n-drop, effets visuels et animations, pré-chargements des images... etc... sont de bonnes candidates pour cette technique.

Compressez votre Javascript

Un conseil qui n'a rien à voir avec jQuery en particulier, la compression YUI de votre code pour une utilisation en production.

La compression YUI réduit drastiquement la taille de vos scripts JS, la page se chargera donc plus vite.

Astuce : Pour une compression maximale avec YUI, déclarer toujours vos variables de cette manière : var ma_variable;

Like it? Tweet it!

About the Author

45 Comments

  1. Bonnes pratiques jQuery | Blog Loïc Morvan : Web 2.0 (2 years ago)

    [...] La plupart de ces remarques sont applicables par extension au langage Javascript et même à tout langage de programmation afin d’en optimiser les performances ou d’en faciliter la lecture. jQuery : Les bonnes pratiques. [...]

  2. Lecture de la semaine #6 | DevZone - Zone de développement web (2 years ago)

    [...] journal du blog nous propose un article sur les bonnes pratiques à avoir avec le framework jQuery jQuery : Les bonnes pratiques (version FR de jQuery Performance [...]

  3. MaDCOw (1 year ago)

    Merci beaucoup pour cet article.
    Même si je connaissait déjà la plupart de ces bonnes pratiques, un petit rappel ne fait jamais de mal.
    Je ne connaissais pas la délégation d’évènement par contre, cela m’explique pas mal de comportements buggués de mes applis et va sauver les performances du projet sur lequel je travaille actuellement.

    Une petite note encore, la plupart de ces bonnes pratiques sont valables aussi pour Prototype et certainement la plupart des autres frameworks JS.

    Par contre, je trouve dommage que l’explication sur le chaînage se limite a écrire moins de code. Cela permet non seulement d’écrire moins de code, mais aussi d’éviter de multiplier les sélecteurs et les affectations de variables inutiles (dans ton exemple, si on en a fini de travailler avec $(‘#traffic_light input.on’), il n’est pas utile d’affecter $active_light)

  4. DocFX (1 year ago)

    Euh, détail piquant aussi, dans les exemples soulignés, n’est-il pas une bonne idée également d’utiliser les callbacks quand on affecte plusieurs fois de suite les attributs css, le bind() et le fade ?

    Sinon, j’aime beaucoup cet article, les premiers points étaient ok pour moi (les ID, les tags par nom, utiliser la fonction each() me fait peur aussi…), mais j’avoue ne pas avoir pensé à tout ça…

    Peut-être serait-il bon pour un futur article de parler des appels AJAX via jQuery ^^

  5. Laetitia (1 year ago)

    Jquery est sûrement la librairie js la plus utilisée, les infos de ce billet sont très intéressantes !

  6. hamma (1 year ago)

    Jquery est sûrement la librairie js la plus utilisée, les infos de ce billet sont très intéressantes !

  7. Magazine mariage naissance (1 year ago)

    J’adore le jQuery car il remplace de mieux en mieux les anim Flash
    et surtout,
    car on peut y faire du référencement pour Google Image en ajoutant l’attribut ALT aux images de slides par exemples.

    • Mist GraphX (9 months ago)

      Article intéressant mais bon trop de jquery ne sert à rien non plus : genre se servir de jquery pour mettre des Alt aux images (comme expliqué dans un commentaire) je vois pas l’utilité autant le coder direct !

      Quand aux pro du référencement qui se sont énervé sur les message de l’article : vous êtes bidons ! les liens sont en rel : noFollow faites une recherche sur votre daube de google que vous aimez tant et vous saurez a quoi ça sert !!! ;-)

      ha les experts du backlink : qui n’ont même pas firebug ou l’idée de regarder le code source : pollueurs !

  8. streaming (1 year ago)

    jQuery c’est vraiment mieux que flash, pourquoi ce compliquer la vie avec flash quand on peux faire plus simple

  9. Spiruline (1 year ago)

    Dommage pour les ID car ils sont unique dans une page :(
    Super article, merci !

  10. Buzz (1 year ago)

    Merci pour toutes ces info sur jQuery, j’ai plusieurs fois essayer de mettre les mains dans le cambouis, et les points dont tu parles mon deja bien eclairer l’esprit ! ;)

  11. JZ (1 year ago)

    Bel article, beaucoup de bon sens mais de bon conseil.

  12. Fred (cotes.fr) (1 year ago)

    merci j’utilisais jquery de temps à autre et ca va me permettre d’optimiser mes scripts.

  13. housse de petit PC portable (1 year ago)

    merci pour cet article. J’éprouve un peu de difficulté avec JQuery

  14. cafetière électrique (1 year ago)

    très bon conseils.

  15. jonat@radiateur electrique (1 year ago)

    Jquery est vraiment une très bonne librairie, très utile.
    Pour les personnes ne maitrisaqnt pas forcement le flash, comme moi, cela ouvre pas mal d’opportunité en matière d’animation de site.
    Et comme évoqué plus haut, niveau référencement, c’est bien lieux que du flash

  16. Radin (1 year ago)

    Un peu obscur pour moi mais je vais essayer de comprendre.

  17. expert comptable paris (1 year ago)

    Oula :s trop compliqué pour moi lol

  18. Poker france (1 year ago)

    Merci pour ce passionnant article, même si j’ai encore beaucoup de lacune sur le sujet ! à bientôt :)

  19. Al3ab (1 year ago)

    « jQuery est une bibliothèque JavaScript libre qui porte sur l’interaction entre JavaScript (comprenant AJAX) et HTML, et a pour but de simplifier des commandes communes de JavaScript. La première version date de janvier 2006″

  20. Photos insolites (1 year ago)

    Merci pour ces conseils !

  21. Thalasso (1 year ago)

    Et bien décidemment quand je vois ça, je me dis que le flash est vraiment mort et enterré.. RIP

  22. idée cadeau (1 year ago)

    Merci pour cette traduction, et notamment m’avoir fait découvrir Yuicompressor que je ne connaissais pas.

    C’est vrai que jquery est devenue une lib incontournable.

    Par contre, je pense que le flash a encore de beaux jours devant lui, notamment grace aux vidéos.

  23. architecte genève (1 year ago)

    Merci pour cette traduction, par contre pas dit que j’arrive à améliorer les performances quand mêmes !

  24. Al3ab (1 year ago)

    JQUERY est le meilleur pour optimiser les scripts.
    Intéressant article
    Merci

  25. starcraft (1 year ago)

    Je suis entièrement d’accord avec ces commentaires.

  26. mini perceuse (1 year ago)

    Merci pour toutes ces infos! Très utile!

  27. Mitigeur douche (1 year ago)

    Excellent tutoriel pour un débutant dans le domaine comme moi! Merci!

  28. Epilation (1 year ago)

    De bonnes bases pour commencer (ou reprendre) les développements en jquery. Une très bonnes librairies très puissantes et a utiliser proprement pour avoir de très bons résulats.

  29. assurance (1 year ago)

    C’est vraiment une classe magique. J’adores ce truc.

  30. Chat (1 year ago)

    Merci pour ce tuto qui ma appris un bon nombres de chose.

    D’ailleurs sa ma permis de décoincer mon projet, j’avais des problèmes de lenteur du a Jquery, j’avais mi mes sélecteurs sur des class en pensant bien faire et …… ^^

  31. Wade Getts (1 year ago)

    I feel very priveledged that this is up on the ‘net and I’m sure glad to have found this place. Have a wonderful weekender.

  32. Logiciel GED (1 year ago)

    C’est vrai que certain dev ne se posent pas la question de l’optimisation pour l’ajax alors qu’il le font pour php par exemple.

    Super article donnant des points de départ sur l’opti ajax ;)

  33. epilation intime (1 year ago)

    Oui en effet, très bons points de départ sur l’opti ajax. J’ai réussi à bien me débrouiller.

  34. Jeune gay (11 months ago)

    Je ne savais pas qu’il y avait de bonnes pratiques en jquery encore merci :)

  35. act exam (11 months ago)

    Je test avec un autre sous domaine parce que tu me le demandes et parce que c toi, puis c’est mon anniversaire alors tu te dois d’être généreux, c’est pas ça ? ^^
    @Sylvain
    Ok, la logique me semble très intéressante, en tout cas. Diversifié ses ancres et ses pages depuis un même host ne peut qu’être positif.

  36. act test (11 months ago)

    Loin d’être un expert dans le référencement, je me demande si les liens des signatures n’a pas un effet « nul » au final pour Google. Spammer les commentaires prends au final beaucoup de temps pour un résultat assez faible.

    Ne serait-ce pas plus intéressant de faire un article, sur un site de communiqués, avec un lien vers son site ?

  37. ccsp certification (10 months ago)

    Quand on blog on passe beaucoup de temps sur son lecteur de flux RSS, mais ce n’est rien comparé au temps passé sur l’admin du blog. Écrire des articles, gérer ses tags, catégories, commentaires etc.

  38. opl (9 months ago)

    2 typos dans des exemples: $(‘manque_apostrophe_finale).etc : $(‘#entryform input) et $(‘#entryform)

  39. Murray Quaranta (9 months ago)

    talented diary you’ve take

  40. jacksonville divorce attorney (9 months ago)

    Obtainable on the net will be web sites this work as referral expert services for you to a variety of solicitors prepared to function low-priced. Most of these sites present free of charge styles get started on that divorce process procedures in addition to suitable assist for a substantially low priced.

  41. why do leaves change color (7 months ago)

    My good friend constantly linked me to this blog site although this really is the first url page I had taken a look at at this point. Im highly amazed and now a reader.

  42. how long to boil corn on the cob (7 months ago)

    My girlfriend normally mentioned this webpage but it’s really the 1st blog page I’ve peruse thus far. I am incredibly fascinated and right away a reader.

  43. al3ab (4 months ago)

    j’aime beaucoup votre article sur les bon pratiques je vais tester tout ça

  44. patrick (3 months ago)

    merci bcp pr cet article!!
    très interessant

Comments

© 2011 WideZine. All rights reserved.