Optimiser un script JavaScript avec Firebug

Un de nos projets requérait une façon simple et aussi inobstrusive que possible d’afficher une image de taille conséquente. Plutôt que d’utiliser l’un des traditionnels clones de lightbox, nous nous sommes orientés vers Zoomer (alors en version 1.7), une classe MooTools permettant de faire un effet de zoom sur une image. Le rendu était assez élégant et correspondait exactement à ce que nous cherchions.

Malheureusement, des problèmes de performance se sont rapidement manifestés, l’animation était loin d’être fluide dans certains cas. Nous avons donc examiné la classe et voici la partie du code qui a attiré notre attention :

startZoom: function(){
	this.position = this.small.getPosition();
	this.timer = this.zoom.periodical(10, this);
	this.big.fade('in');
},
 
//....
 
zoom: function(){
	if(!this.dstPos) return;
	var steps = this.options.smooth;
	var current = {
		left: this.big.getStyle('left').toInt(),
		top: this.big.getStyle('top').toInt()
	};
	var dst = {
		left: parseInt((this.dstPos.x - this.position.x) * (1 - this.bigSize.width/this.smallSize.width)),
		top: parseInt((this.dstPos.y - this.position.y) * (1 - this.bigSize.height/this.smallSize.height))
	};
	var now = {
		left: current.left - (current.left - dst.left)/steps,
		top: current.top - (current.top - dst.top)/steps
	};
	this.big.setStyles(now);
}

La méthode zoom() est exécutée tous les centièmes de secondes avec à chaque fois deux appels à getStyle(), une opération plutôt exigeante en ressource,  sur lesquels est appliqué toInt(). Nous avons donc modifié le script de façon à limiter le nombre d’opérations effectuées dans la méthode zoom().

startZoom: function(){
	this.position = this.small.getPosition();
 
	/** precalculations **/
	this.ratio = {
		x : 1 - this.bigSize.width / this.smallSize.width,
		y : 1 - this.bigSize.height / this.smallSize.height
	};
	this.current = {
		left: this.big.getStyle('left').toInt(),
		top: this.big.getStyle('top').toInt()
	};
 
	this.timer = this.zoom.periodical(10, this);
	this.big.fade('in');
},
 
//.....
 
zoom: function(){
	if(!this.dstPos) return;
	var steps = this.options.smooth;
 
	var current = this.current;
 
	var dst = {
		left: parseInt((this.dstPos.x - this.position.x) * this.ratio.x),
		top: parseInt((this.dstPos.y - this.position.y) * this.ratio.y)
	};
 
	this.current.left-= (current.left - dst.left) / steps;
	this.current.top-= (current.top - dst.top) / steps;
 
	this.big.setStyles(this.current);
}

Pour estimer l’impact des modifications, nous avons utilisé cette incontournable extension Firefox qu’est Firebug. Si comme moi vous travaillez régulièrement sur des scripts JS, il est probable que vous connaissez déjà l’objet console ainsi que sa méthode log() qui permet d’afficher la valeur d’une ou plusieurs variables. Les fonctions à utiliser dans notre cas sont console.time(string) et console.timeEnd(string). La première initialise un timer identifié par la chaîne de caractères donnée, tandis que la seconde permet de le stopper et d’en afficher la valeur. Nous avons procédé comme suit : mis les calculs effectués dans la méthode zoom() dans une boucle avec 10000 itérations, initialisé le timer avant la boucle et affiché sa valeur après. Au final, la fonction originale prenait entre 500 et 600ms pour s’effectuer sur Firefox avec Firebug activé, la version modifiée seulement entre 9 et 12ms. Nos modifications ont été intégrées dans la version 1.8 de la classe disponible sur la forge MooTools.

Autres fonctions utiles pour optimiser votre code, généralement lorsque vous ne parvenez pas à identifier le bottleneck du script : console.trace(), console.profile(string), console.profileEnd() et console.count(string). Voir l’API Console sur le wiki de Firebug.

Ecrire une réponse