Performances des packers javascript

Les librairies et frameworks javascript sont de plus en plus nombreux et de plus en plus complets. Ca, c’est une bonne nouvelle, mais la conséquence logique est que leur taille augmente jusqu’à un point qui commence à devenir problématique. Heureusement, des outils de “compression” tels que JSMin sont apparus ; ils permettent de réduire sensiblement la taille des scripts en supprimant les commentaires, l’indentation, et autres caractères inutiles. Le principe est de conserver une version complète et documentée des scripts pour le développement, puis, au moment de la mise en production, les fichiers passent dans cette moulinette de compression qui les “amaigris”.

Depuis quelques temps, une autre technique de compression emerge. Au lieu de simplement purger le code de tous les caractères inutiles, le code est “empaqueté” (packed) dans une fonction qui contient l’agorithme permettant de décompresser le paquet. Ainsi il est possible d’utiliser des méthodes de compression plus efficaces (changement de base, remplacement de patterns, etc.) et obtenir des fichiers encore plus petits, mais totalement illisibles. Ces solutions ont été très vites adoptées par de nombreux projets et sites web, mais sont-elles vraiment si efficaces ?

Des fichiers illisibles

Le principe intrinsèque des packers oblige à brouiller (obfuscate) le code javascript. Qu’est-ce que cela implique ?

Exemple :

alert('toto');
eval(function(p,a,c,k,e,r){e=String;if(!''.replace(/^/,String)){while(c--)r[c]=k[c]||c;k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('0(\'1\');',2,2,'alert|toto'.split('|'),0,{}))

La première conséquence la plus évidente est que les fichiers deviennent illisibles. Certains y voient un bon moyen de “protéger” leur code contre des regards indiscrets, mais est-ce serieux ? Non, car tous ces algorithmes sont reservibles.

Le problème d’un fichier illisible est qu’il est impossible à débugger. Il faut obligatoirement passer par une version non compressée, disponible en théorie sur la plateforme de développement. Mais comment faire si le bug n’est pas reproductible sur la plateforme de developpement ?

Le second problème concerne les performances. Combien de temps prend l’étape de décompression côté client ?

Quand le gain se transforme en perte

Pour pousser plus loin l’analyse, j’ai effectué quelques mesures avec le framework MooTools complet, en utilisant 3 versions :

  • non compressée ;
  • compressée avec JSMin ;
  • compressée avec le packer de Dean Edwards.

Le navigateur utilisé est Firefox 2.0.0.4 sous Microsoft Windows XP.

Le test porte sur 3 choses :

  • la taille ;
  • le temps moyen de chargement ;
  • le temps moyen de rendu d’une page incluant se fichier.

Pour calculer le temps de chargement, j’ai utilisé l’extension Lori pour Firefox en accedant aux fichiers javascript en http.

Pour calculer le temps de rendu, le code de test est le suivant ({version} est remplacé successivement par “original”, “jsmin” et “packed”):

<html>
<head>
	<script type="text/javascript">
	<!--
		var start = new Date().getTime();
	-->
	</script>

	<script type="text/javascript" src="mootools.{version}.js"></script>
	<script type="text/javascript">
	<!--
		var stop = new Date().getTime();
		alert('loaded in ' + (stop - start) + 'ms')
	-->
	</script>
</head>

<body>
	<h1>LOADED !</h1>
</body>
</html>

Résultats

version taille (Ko) moyenne chargement (ms) moyenne rendu (ms)
originale 180 360 230
jsmin 73 205 230
packed 43 156 440
version gain taille (Ko) gain chargement (ms) gain rendu (ms)
jsmin 107 155 0
packed 137 204 -210

Le temps de chargement et de rendu sont à considérer relativement entre eux. Ils dependent en effet de la bande passante pour le premier et de la puissance de l’ordinateur du client pour le second. Par contre, l’écart relatif est le même.

version gain taille (%) gain chargement (%) gain rendu (%)
jsmin 59% 43% 0%
packed 76% 57% -91%

Interprétation

L’analyse des résultats est sans appel. La version “packed” permet de gagner 76% en taille, il n’y aucun doute sur le fait que c’est le système de compression le plus efficace. Ce gain de place permet de gagner environ 57% en temps de chargement ce qui est appréciable. Par contre, à cause de l’étape de décompression imposée par ce système, le temps d’interprétation du javascript est pratiquement doublé !

Conséquence agravante : il faut savoir que, pendant que le javascript se charge en mémoire dans le navigateur, le processus de rendu graphique de la page est bloqué. Ce problème est bien connu des webmasters qui utilisent une régie publicitaire externe par exemple. Ainsi, on observe une certaine latence au moment de l’affichage de la page, particulièrement inconfortable.

De plus, si le temps de chargement est réduit à zéro une fois le fichier mis en cache navigateur, le temps de rendu est, lui, incompressible. Ainsi, la page utilisant le javascript “packed” mettra toujours pratiquement deux fois plus de temps à s’afficher.

Il est interressant de noter qu’un fichier compressé avec JSMin ne présente pas ce problème, tout simplement parceque le code est strictement le même que la version originale : les commentaires et l’indentation supprimés n’impactent en rien le temps de rendu.

Conclusion

Les packers javascript permettent effectivement de gagner en taille. Mais il ne faut pas perdre de vue les autres aspects tout aussi essentiels que la taille : lisibilité, maintenabilité, et surtout, temps de décompression du fichier par le navigateur. Sur les tests effectués, ce dernier est tellement important qu’il absorbe largement le gain en temps de chargement.

Le système de compression classiques comme JSMin offrent, eux, un gain acceptable en taille, sans présenter tous les inconvenients des packers : le fichier reste lisible et débuggable, et met autant de temps à s’executer que la version originale.

Post a comment.