Benchmark des sélecteurs jQuery

Logo jQuery

jQuery

Je suis tombé sur un article intéressant il y a quelques temps: Your jQuery now with 67% less suck. J’y ai appris par exemple qu’il y a désormais plus de sites internet qui utilisent l’excellent jQuery que Flash.

Mais on y découvre également des astuces pour permettre à son code jQuery d’être plus performant. Beaucoup de ces astuces sont basées sur la rapidité des sélecteurs utilisés à profusion par jQuery.

On nous dit par exemple que $("#id").find("p"); est deux fois plus rapide que $("#id p");, pour un effet égal.

J’ai voulu aller plus loin dans cette analyse de rapidité des sélecteurs, en faisant un benchmark.

Protocole

Le code source du benchmark est disponible, utilisable et modifiable. Le projet est sur github et je vous invite à y jeter un coup d’œil.

Certains tests ne sont pas directement comparables, comme par exemple celui qui concerne le sélecteur :even qui renvoie les éléments pairs.

Tous les sélecteurs ont été testé en utilisant container.find(selecteur), c’est le moyen que j’ai trouvé pour avoir des résultats comparables entre sélecteurs. On verra que ce choix a pu avoir un impact sur les benchmarks eux‐même.

Comparaison des sélecteurs

Ces tests ont été effectués sous Chrome, la hierarchie est globalement la même sous d’autres navigateurs à quelques exceptions près. Mais pour comparer les sélecteurs entre eux, j’ai préférer le faire avec un seul navigateur.

Nous verrons par la suite une comparaison des navigateurs.

Les plus rapides

Sélecteurs les plus rapides (échelle log)

Sélecteurs les plus rapides (échelle log)

Le palmarès est à peu près le même pour Chrome et Firefox (on note des différences avec Opera et IE, mais nous y reviendrons). Attention, l’échelle est logarithmique !

Sans aucune surprise, le sélecteur #id est le plus rapide. Il profite évidemment de la fonction native document.getElementById() implémentée par les navigateurs.

On remarque également que sélectionner un élément avec son identifiant est à peu près 5 fois plus rapide que de le faire en connaissant sa balise HTML, et que ce sélecteur est le deuxième plus rapide.

Les plus lents

Sélecteurs les plus lents (échelle log)

Sélecteurs les plus lents (échelle log)

Pour mettre en relief ces données, il convient de comparer les échelles avec le graphique du dessus. Le sélecteur .class permettait d’effectuer 60000 opérations par seconde. Ici, le sélecteur [attr!=val] a une vitesse de 300 opérations par seconde. Le second est donc 200 fois plus lent !

On note également que d’utiliser la méthode .find() sur un objet jQuery semble très pénalisant, avec une performance parmi les plus mauvaises du benchmark. Cette mesure va à l’encontre du conseil donné par l’article Your jQuery now with 67% less suck. Mais nous y reviendrons.

Sélecteurs classiques

Sélecteurs de base (échelle log)

Sélecteurs de base (échelle log)

Les sélecteurs de base, liés aux attributs id, class ou aux balises. L’échelle logarithmique est trompeuse, mais c’était le seul moyen de tout mettre sur le même histogramme : le sélecteur d’identifiant est 4 fois plus rapide que le sélecteur de classe.

On remarque aussi que Internet Explorer 8 est un veau. Ô surprise. Il est 19 fois plus lent que Chrome sur le sélecteur #id, dans ce benchmark.

Parcours du DOM

jQuery permet de sélectionner un élément en fonction de la hierarchie de ses parents. Par exemple, avec le code HTML suivant, on dispose de plusieurs moyens pour sélectionner le paragraphe contenu dans l’élément div.

<div>
  <p>Balise à sélectionner</p>
</div>
<p>Ne pas sélectionner</p>

On peut utiliser une des solutions suivantes.

var withSelector = $("div p");
var withFind = $("div").find("p");
var withArguments = $("div", "p");

Cependant, les benchmarks montrent des performances différentes pour les trois méthodes.

Parcours de DOM (échelle log)

Parcours de DOM (échelle log)

Il semble que la solution préconisée en général soit la plus lente dans la configuration testée ici ! En effet, la méthode .find() a montré les performances les plus faibles en étant 100 fois plus lente que le sélecteur classique a b.

Sélecteurs d’attributs

Sélecteurs d'attributs (échelle log)

Sélecteurs d’attributs (échelle log)

Ces sélecteurs ont à peu près les mêmes performances, sauf le sélecteur [attr!=foo] qui permet de sélectionner des valeurs différentes de celle indiquée. On peut également remarquer que Opera semble être particulièrement optimisé pour traiter ces requêtes. En effet, Opera est en général un peu moins de 10 fois plus rapide que Chrome et plus de 50 fois plus rapide que IE8 sur ces sélecteurs.

Sélecteurs liés aux formulaires

Sélecteurs liés aux formulaires (échelle log)

Sélecteurs liés aux formulaires (échelle log)

J’ai regroupé au sein d’un test spécifique tous les sélecteurs permettant d’accéder à des champs de formulaires. Ce qui est intéressant, c’est qu’on trouve des performances assez médiocre en comparaison des sélecteurs d’attribut. Pourtant, ces sélecteurs font en théorie le même travail !

// Ces deux sélecteurs sont équivalents
// mais n'ont pas les mêmes performances
var passwordInput = $(":password");  // 10x plus lent
var passwordAttribute = $("[type='password']");

Pour confirmer, j’ai créé un test spécifique permettant de comparer les sélecteurs dans des conditions identiques.

Comparaison des sélecteurs équivalents (échelle log)

Comparaison des sélecteurs équivalents (échelle log)

Globalement, on gagne énormément en performance en n’utilisant pas ces sélecteurs spécifiques, que sont :input, :password etc… Seuls :enabled et :selected semblent correctement gérés par les navigateurs.

Performances des navigateurs

Ce benchmark n’avait pas à l’origine pour but de comparer les navigateurs. D’ailleurs, je n’ai pas IE9 ! Si certains sont intéressés pour faire leurs propres tests, le code source de ce benchmark est disponible sur github. Vous pouvez l’utiliser, le modifier et soumettre des modifications.

Malgré tout, je ne résiste pas à l’envie de faire un comparatif global.

Performance globale sur les sélecteurs testés (échelle log)

Performance globale sur les sélecteurs testés (échelle log)

Sur ce benchmark, Opera se démarque en partie grâce aux optimisations liées aux sélecteurs d’attributs. Chrome s’en sort mieux que Firefox. Et enfin Internet Explorer 8 (version obsolète, à leur décharge), est clairement à la ramasse.

Laisser un commentaire