Modification des propriétés d’un composant visuel : augmenter les performances

Suite à un projet qui demandait de modifier continuellement les propriétés de plusieurs composants visuel dans un MOUSE_MOVE, j’ai du modifier le fonctionnement interne de ceux ci car le gaspillage des ressources était assez énorme.

Dans l’ancienne version des composants, à chaque modification de la valeur d’une propriété, le composant devait ce re-dessiner, hors si on modifie plusieurs propriétés a la suite le composant devait être redessiné pour chaque propriété …

Dans cette méthode (un simple exemple) exécuté par un MOUSE_MOVE, 4 propriétés sont modifiés ce qui demande au composant de ce redessiner 4 fois : 3 fois de trop quand on recherche un usage modéré des ressources :

function evtStageMouseMove(ev:Event) {
	composant.couleurFond = _clrFond;
	composant.couleurTexte = _clrTexte;
	composant.couleurContour = _clrContour;
	composant.texte= _texte;
}

Le probleme ce situe au niveau de la définition des propriétés, quand une propriété change de valeur, on demande au composant de ce re-dessiner :

public function set couleurFond(val:uint):void {
	if( this._clrFond != val ){
		this._clrFond = val;
		this.dessiner();// méthode qui va dessiner le composant
	}
}

Pour éviter l’effet indésirable il ne faut plus appeler la méthode qui dessine le composant dans le « setter », mais plutôt enregistrer un évènement pour que le composant sache qu’il doit ce redessiner lorsque la tête de lecture change de « frame », de cette façon on peut ce permettre de modifier plusieurs propriétés à la suite avec une seule re-création visuelle, donc plus le composant est complexe et plus l’économie de ressource est grande !

Les modifications à apporter sont simples :

  1. Enregistrement d’un évènement ENTER_FRAME dés qu’une propriété est modifié.
  2. Dans l’ENTER_FRAME on appelle la méthode qui doit créer le composant.
  3. Effacement de l’évènement ENTER_FRAME aprés la re-création du composant.
// un "setter" d'une propriété quelconque
public function set couleurFond(val:uint):void {
	if( this._clrFond != val ){
		this._clrFond = val;
		this.redessiner();// méthode qui va enregistrer l'évènement ENTER_FRAME
	}
}
 
// enregistrement de l'évènement ENTER_FRAME
private function redessiner():void {
	this.addEventListener(Event.ENTER_FRAME, dessiner);
}
 
// méthode utilisé pour dessiner le composant
private function dessiner(ev:Event = null):void {
	// Faire ici tous les ajouts des éléments graphique + tous les dessins voulu pour créer le visuel du composant
	// .....
 
	// effacer l'évènement ENTER_FRAME
	this.removeEventListener(Event.ENTER_FRAME, dessiner);
}


J’ai chronométré l’ancienne façon de faire et la nouvelle pour vérifier les apports des modifications, le résultat est éloquent :
pour 7 propriétés à modifier pour 1 composant, le tout exécuté 1000 fois de suite dans une boucle (vitesse swf = 30ips)
ancien système : 1922 Millieme (1,9 sec)
nouveau système : 100 Millieme (0,1 sec)
Les modifications ont permis de diviser par 19 le temps utilisé par le composant pour sa création .. c’est loin d’être négligeable :)


Il existe plein d’autres manières d’économiser des ressources et la plupart sont tout à fait logique, tel que :

  • Ne pas utiliser un Sprite quand un Shape suffit.
  • Ne pas utiliser un MovieClip quand un Sprite suffit -> Il est d’ailleurs très rare d’avoir besoin de MovieClip pour un composant visuel et pourtant il suffit de faire une recherche sur google code pour remarquer qu’un gros paquet des composants visuels actionscript utilisent MovieClip comme classe mère, pourtant quasiment aucun de ces composants utilisent les propriétés/méthodes propre à MovieClip.
  • Éviter les composants adobe, ils sont bons, complets mais lourd.
  • Ne pas utiliser un ENTER_FRAME quand un MOUSE_MOVE suffit.
  • Limiter le nombre et l’utilisation des TextField, cette classe est très lourde.
  • Quand c’est possible il faut déclarer les classes et méthodes avec le mot clé final (permet au compilateur de faire un gros travail d’optimisation).
  • Éviter tant que possible les méthodes de la classe Math (la plupart peuvent être remplacés facilement avec un peu de code, tel que min/max/sqrt/abs).
  • …etc

Laisser un commentaire

*