Le JavaScript intervient de plus en plus, quelque soit le type de site internet. Du simple carrousel à l’affichage d’une carte en 2D isométrique (comme le plugin pp3Diso), en passant par des effets spéciaux, JavaScript est là, pratiquement sur toutes les pages.
Et comme il est exécuté côté client, il n’est pas rare qu’un mauvais codage ralentisse sensiblement l’affichage d’une page. Sans compter avec les anciens navigateurs ou même les smartphones qui ne sont pas forcément des bêtes de course.
Une fois que vous aurez mis en place les préconisations extérieures au code, voici quelques astuces qui sont liées directement au code.
Les boucles
Vous avez forcément une boucle qui traîne dans votre code JavaScript. Sachez que l’expression qui permet de mettre fin à la boucle (la condition) est recalculée à chaque fois. Voici un mauvais exemple :
for(var i = 0; i < maChaine.length; i++) { // ... }
la longueur de la chaine va être recalculée à chaque fois : pas bien. Voilà comment coder cette boucle :
var l = maChaine.length; for(var i = 0; i < l; i++) { // ... }
Vous gagnerez en rapidité.
Évidement, vous constaterez une différence uniquement sur de longues boucles. Mais bon, il est toujours bon de prendre de bonnes habitudes.
Quelques calculs
J’ai régulièrement besoin de transformer une chaine de caractères en entier. Il existe une fonction qui permet de faire cela : parseInt.
Le problème de cette fonction, qui est relativement rapide, c’est que si on l’utilise tel quel, on risque d’avoir quelques surprises et notamment lorsque la chaine de caractères commence par un zéro.
En effet, parseInt(‘0777’) donnera 511 comme résultat alors que parseInt(‘777’) donnera 777.
Tout simplement parce que ‘0777’ est interprété comme un chiffre en notation octale (base 8) alors que ‘777’ est en notation décimal (base 10).
Pour contrer cela, il suffit d’indiquer un second paramètre : parseInt(‘0777 », 10) donnera bien 777 car on a précisé la base en second paramètre.
Oui, mais… dans ce cas, on a une fonction qui est, en moyenne, 2000 fois plus lente !
Alors voici plusieurs possibilité plus rapides que parseInt :
var chaine = '0756'; //-- 1ere possibilité : la plus rapide en moyenne var result = chaine | 0; //-- autre possibilité var result = chaine >> 0; //-- une dernière var result = ~~(chaine);
Comme vous le voyez, vous avez le choix. Ces variantes sont environ 2000 fois plus rapide (tout dépend du navigateur, de l’OS, de la vitesse de votre machine, …)
Un peu de jQuery
jQuery est utilisé à tout va et pour n’importe quoi. C’est un peu normal, il simplifie grandement le développement. Mais bon, parfois, vous pouvez vous en passer, hein ! Mais ce n’est pas le sujet.
Pour masquer un objet, vous pouvez utiliser cette fonction :
$('#mon_objet').hide();
Rien de plus simple… Sauf que c’est lent, très lent !
Alors, utilisez plutôt cette solution :
$('#mon_objet').css('display', 'none');
Beaucoup plus rapide.
Lorsque vous faites référence à un objet, mettez la référence en cache si vous y faites plusieurs fois appel :
//--- ne pas faire : var display = $('#objet').css('display'); var x = $('#objet').css('left'); var y = $('#objet').css('top'); //--- faites plutôt ceci : var obj = $('#objet'); var display = obj.css('display'); var x = obj.css('left'); var y = obj.css('top');
Et, comme d’habitude, tout ceci est à modifier en fonction de vos besoins et de chaque cas particulier que vous allez rencontrer.
Pensez d’abord qu’il faut optimiser les boucles. Ce qui se trouve dans les boucles est, normalement, répété beaucoup de fois. Safari dispose d’un très bon outils pour visualiser les fonctions qui prennent du temps : le profiler. Vous pouvez le démarrer et le stopper directement depuis le JavaScript, ce qui vous permettra de profiler une partie du code :
//-- démarrage du profilage console.profile(); //--- code ... ... //-- Fin du profilage console.profileEnd();
Vraiment très pratique ! Et c’est fonctionnel également avec la version Windows.
j’apprécie beaucoup cette phrase :
jQuery est utilisé à tout va et pour n’importe quoi. C’est un peu normal, il simplifie grandement le développement. Mais bon, parfois, vous pouvez vous en passer
En tout cas, merci pour ces astuces.
Moi, j’avoue que j’aimerais quelques détails sur les débugger Javascript …
J’ai utilisé firebug, mais je m’y perds un peu.
Kéké qui n’est pas fana de JAVA-Script … même s’il en a déjà fait au taf, dont une partie Serveur-Side ! (geuuu …)
Pour analyser les performance javascript, dynatrace est un incontournable. Il permet notamment de profiler IE 6/7/8 qui sont les navigateurs les moins performants mais les plus utilisés.
Les exemples de code incorrects cité ici sont valides. J ajouterai quelques points.
Souvent l’articulation server-cient doit etre améliorée afin d eviter des requetes ajax inutiles. Cela implique cote server de savoir chainer plusieurs action et de servir les resultats dans une seue reponse json. Cote client il est necessaire d avoir un layer de donnees et du templating afin de pouvoir reafficher un contenu stocke en memoire, plutot que d appeler le serveur à nouveau.
La communication javascript-dom est plus lente que de l’execution de javascript lui-meme. Il faut eviter les acces inutiles au dom:
-le dom n est pas un layer de donnees, mais sert au rendering
-event delegation permet d eviter d avoir a selectionner des collections d’elements pour y accrocher des fonction
-inserer de l html deja stylé (avec des classes) permet d eviter d avoir a selectionner des collections d’elements pour les modifier
-l utilisation d un memoiser permet de recuperer en memoire les node deja selectionnés auparavent
Attention au profiler Safari, il est relativement imprecis.
Pour ton exemple $(‘#mon_objet’).hide();
le plus rapide c’est naturellement le js natif :
document.getElementById(‘#mon_objet’).style.display = « none »;
et un tout petit detail pour finir, imo la variable « l » prete a confusion, ca ressemble a un « 1 ». Personellement je prefere « len ». La declaration de variable peut se faire dans la boucle :
for(var i = 0, len = maChaine.length; i < len; i++) {
Je suis curieux de savoir pourquoi tu a régulièrement besoin de transformer une chaine de caractere en entier. Si veux passer des donnee du server à javascript, alors il faut le faire directement vers javascript et creer des variables.
Je n’ai pas cité Dynatrace car j’ai eu des incohérences dans les résultats. Je préferais attendre avant de le citer. Mais oui, c’est un très bon outils.
Pour reprendre donc tes interrogations :
– les bouts de codes « incorrects » sont valides. Oui, ils le sont. Ils servent juste d’exemple de code « lent ».
– le plus rapide en JS natif : c’est toujours vrai, en effet. Sauf que la compatibilité n’est pas là. Il faut donc tenir compte des différents navigateurs (je n’ai rien contre Microsoft, Max, Mozilla et Linux et compagnie). D’ailleurs, je vous renvoie vers cette page pour les problèmes de compatibilité : http://www.quirksmode.org/dom/w3c_core.html
– la déclaration des variables dans la la définition de la boucle : en fait, cela semble dépendre du navigateur. Après plusieurs tests de mon côté, j’ai mis la déclaration en dehors. Mais ça vaudrait le coup que beaucoup de mon test : http://jsperf.com/for-loop-speed-test/3
Enfin, là, on parle de miettes quand même 🙂
Et sinon, j’ai besoin de transformer les strings en integer car ces strings proviennent d’un utilisateur et qu’elles peuvent contenir le fameux zéro du début. Il m’arrive également de mettre des variables directement dans l’id d’un objet par exemple et de les récupérer après pour les additionner. Enfin voilà, plein de cas particuliers.
Merci pour cet article orienté ‘pratique’ et pour le profiler dynatrace qu’évoque OLIVVV juste au dessus