jQuery : optimiser l'utilisation des sélecteurs CSS
JQuery est une formidable librairie JavaScript car elle offre une grande souplesse et une utilisation simple. Il est cependant important de bien comprendre son fonctionnement pour éviter les débordements liés à une joie mal maîtrisée.
S’il est très facile d’utiliser les sélecteurs CSS de jQuery, je constate de ci de là que leur utilisation n’est pas toujours optimale … quand elle l’est déjà un tant soit peu.
Alors on se retrousse les manches et c’est parti pour un petit cas pratique sur les sélecteurs CSS jQuery, plus une petite récap’ pour grapiller du temps et des lignes de code ;-)
§Le cas pratique
J’ai pensé à une chose : plutôt que vous papillonniez en lisant cet article, j’ai fait en sorte que vous puissiez y prendre part. JQuery est très divertissant - certainement plus que votre voisine d’en face - alors tant qu’à me lire, autant optimiser la compréhension ;-)
Pour cela il vous faut 2 choses :
- un bac à sable HTML / jQuery concocté par mes soins
- l’inévitable extension Firebug pour bénéficier d’une console digne de ce nom (entre autre)
§Principe de la sélection CSS de jQuery
Que celui qui s’est lancé corps et âme dans jQuery sans lire la documentation lâche un com’ ! Elle est suffisamment complète pour éviter la plupart des questions du genre comment je fais pour …
.
Maintenant que vous avez le document en main, nous allons jouer avec jQuery pour récupérer ce que nous voulons. Les personnes n’ayant pas Firebug comprendront la logique du code sans même avoir à le regarder :
1 |
|
Magique non ?
§Comprendre la sélection CSS de jQuery
Les résultats sont propres mais n’est pas parce que ça marche que c’est bien. La preuve, tous les exemples ci-dessus ne sont pas du tout optimisés.
Alors comment savoir si un sélecteur est optimisé ou pas ? La réponse n’est pas systématique car elle dépend exclusivement de votre rigueur et du DOM à interroger. Plus il sera touffu et plus votre sens aigü de la performance sera sollicité.
Reprenons les exemples ci-dessus pour le transposer en JavaScript old-school. C’est le meilleur moyen de sentir le piège … ou pas.
1 |
|
Il y a 2 erreurs dans cette sélection :
- sélectionner
body
.getElementsByTagName()
oblige à parcourir tous les nœuds du document (1000 s’il y en a 1000) alors qu’on n’en veut qu’un … et qu’il ne peut y en avoir d’un ; - on sélectionne ensuite tous les
p
du body. Autant le faire dès la première fois car là encore c’est tous les nœuds contenus dansbody
qui sont parcourus … y compris l’énorme liste à puces !
1 |
|
La sélection est ici trop générique. On voit bien que l’on est obligé de charger tous les éléments ul
du DOM pour les filtrer.
1 |
|
C’est probablement la dernière chose à faire. Cassez les genoux de toute personne écrivant un tel sélecteur : il mérite d’animer le BigDill rien de plus !
Dans ce cas de figure, c’est TOUT le DOM qui est chargé (75 éléments) pour ensuite boucler sur un filtre. Cette boucle n’est pas optimisée mais ce n’est pas ce que l’on souhaite travailler aujourd’hui ;-)
1 |
|
Comme dans le premier cas, le document.getElementsByTagName()
charge tout le DOM pour le filtrer, ne récupérer que le premier élément et, seule opération non coûteuse, utiliser son dernier enfant.
Ce n’est pas la pire des exemples mais là encore on peut optimiser les choses.
1 |
|
Un sélecteur par classe ne devrait être qu’un cas extrême, quand on ne peut se fier à une balise donnée. Car de manière générale, le getElementsByTagName('*')
est à bannir. Charger tout le DOM est une folie furieuse.
La bonne idée ici est l’utilisation du symbole >
. Cela se traduit par .childNodes
et nous verrons plus bas pourquoi c’est mieux.
§Et maintenant, optimisons
S’il fallait résumer l’optimisation en 3 points, voici ce que je donnerai :
- jamais de sélecteur vague
- toujours un ID (#
) en tête de sélecteur - utiliser au maximum les objets natifs (
firstChild
,childNodes
etc.) : ils évitent d’interroger tout le DOM
L’ennemi des sélecteurs CSS ce sont les boucles. Plus elles ont à brasser d’éléments,
plus elles sont longues. getElementsByTagName()
cache une boucle : JavaScript scanne
tout le DOM pour trouver un nœud ayant un tagName
correspondant.
S’il faut l’utiliser, c’est en aval d’un sélecteur ayant déjà trié une bonne partie du document.
Votre meilleur ami est getElementById()
. Comme son nom l’indique il ne retourne qu’un seul élément et surtout, il est incroyablement rapide. Utilisez-le dans un maximum de cas mais attention tout de même : trop d’ID nuit à la structure du document le rendant ainsi trop rigide.
Il en est de même du parcours des objets natifs des nœuds du DOM. Cela signifie que dès que vous changer la tête de votre HTML, le JavaScript peut en pâtir.
Des fois il faudra faire quelques concessions de performances pour éviter de réécrire votre code au moindre changement … ou parce que la génération est dynamique et difficilement maîtrisable.
Grâce à ces informations, nous pouvons reprendre nos exemples mais de manière optimisée :
1 |
|
§Évitons les doublons : chaînons !
Les CSS c’est un peu fatiguant alors terminons sur une autre utilisation de jQuery parfois sous-employée à cause d’un manque de compréhension : les chaînes. jQuery renvoie des objets et permet de réutiliser/filtrer les résultats avec un seul sélecteur.
Voici un extrait de code largement optimisable :
1 |
|
Tout est correct sauf qu’on répète plusieurs fois le même sélecteur au lieu d’utiliser la chaîne disponible. jQuery optimise la sélection d’un élément déjà sélectionné au préalable mais n’empêche, au lieu d’interroger 5 fois #intro
, nous n’allons plus le faire qu’une seule fois :
1 |
|
Tout se suit jusqu’à la fonction children()
qui modifie le sélecteur de départ et applique la suite de la chaîne à cette nouvelle sélection.
Une autre optimisation consiste à déplacer la déclaration CSS cursor
dans la classe .jevaisdisparaitre
de l’hypothétique feuille de style. Essayez de dissocier au mieux fond et forme : ça évite BEAUCOUP de modifications de code pour des ajustements esthétiques.
§Conclusion
Optimiser ses sélecteurs n’est finalement pas si difficile que ça quand on comprend comment fonctionnent les rouages internes. Il est évident que les gains peuvent être minimes sur de petites pages. Il s’agit cependant d’une gymnastique à maîtriser : ce n’est pas en arrivant sur de gros volumes qu’il faudra apprendre à sélectionner proprement.
Et comme les petites rivières font les grands fleuves
, ces petites économies pourraient vous sauver la vie sur des applications full-AJAX ou qui sait, quand vous travaillerez chez Netvibes ;-)