Olivier El Mekki

Optimiser l’utilisation des sélecteurs JQuery

Dans un article précédent, je vous ai montré comment construire des sélections complexes avec JQuery. Il est temps maintenant de déconstruire.

Staicu Ionut a récemment publié un article dans lequel il revient sur une “grosse erreur” dans la considération des performances des sélecteurs de JQuery : considérer que la sélection est plus rapide lorsque l’expression de recherche est plus spécifique.

Huge mistake!

Pour ceux qui ne saisissent pas bien le terme, être plus spécifique, c’est être plus précis. Soit le code HTML suivant :

1
2
3
4
5
6
7
8
9
10
<body>
  <ul id="menu">
    <li><a href="lien">lien</a></li>
    <li><a href="lien">lien</a></li>
    <li><a href="lien">lien</a></li>
  </ul>
 
  <p>paragraphe</p>
  <p>paragraphe</p>
</body>

On considérait que pour sélectionner les liens, il valait mieux utiliser :

$( "ul li a" )

Plutôt que le moins spécifique :

$( "a" )

Je soupçonne cette recommandation d’être dérivée des pratiques du CSS, où il est préférable de toujours être le plus spécifique possible si on ne veut pas avoir des surprises dans l’ordre de priorité des règles.

Selon les tests de Staicu, réalisés avec la fonction profile() de firebug, la seconde forme est pourtant significativement plus rapide.

La raison en est, après coup, évidente : dans la première forme, JQuery cherche d’abord tous les ul, puis tous les li internes, puis tous les a internes.

Les solutions

Pour commencer, il est toujours préférable d’utiliser un id ou une class plutôt qu’une chaîne de sélection. Ainsi, plutôt que de faire $( “#menu li a” ), il est préférable de donner la classe .menuLink aux a et de faire $( “.menuLink” ). Cela semble évident pour ce cas simple, ça l’est moins dans des chaînes complexes. Une règle simple à retenir : la chaîne la plus courte est toujours la meilleure.

Une autre possibilité d’optimisation apparaît alors. Si on place à la base de chaque sélecteur un id ou une class, pourquoi ne pas directement passer par les fonctions builtins de javascript? J’ai moi-même effectué des tests avec le profiler de firebug et j’ai obtenu des résultats significatifs me laissant penser ceci : il est plus rapide d’utiliser getElementById ou getElementsByClassName puis de s’en servir comme contexte dans un sélecteur JQuery, plutôt que de selectionner le tout en une expression JQuery.

Ainsi :

$( "#menu li" )

peut être remplacé, pour optimiser les performances, par :

var context = document.getElementById( "menu" ) ;
$( "li", $(context) ) ;

Voici les deux fonctions que j’ai utilisé dans firebug pour faire mes tests :

function a(){ for (var i=0;i&lt;10;i++){ $( "#menu li" ) } }
function b(){ for (var i=0;i&lt;10;i++){ var c=document.getElementById( "menu" ) ; $( "li", $(c) ) } }

Après avoir profilé ces deux fonctions individuellement une dizaine de fois, il s’avère que la fonction a() s’exécute généralement dans le double du temps de la fonction b().

Plutôt refroidissant… Un petit bémol pourtant : nos machines double processeurs avec un giga de RAM peuvent très bien utiliser les techniques les plus lentes de sélection sans même que nous nous en rendions compte. Ce problème ne risque en fait que d’affecter les applications desktop-like de type web3 (comme greader, ou le promis google desktop), qui font un usage intensif de javascript. De quoi nous laisser le temps de voir venir, surtout qu’il y a…

Une bonne nouvelle

John Resig (le créateur de JQuery) travaille actuellement sur un nouveau moteur de sélection. Il estime qu’il sera quatre fois plus rapide que le moteur actuel. Time will tell…

Laisser un commentaire