Recevez les mises à jour gratuites du blog par Email : »» Garanti sans spam indésirable ««

Optimiser et structurer son code JavaScript

de Mimie le 1 avril 2010

Rubrique : Programmation

Placement

Nous voyons un peu partout des recommandations de la part des grands comme Yahoo! par exemple avec son « Best practices for Speeding Up Your Web Site » sur le fait qu’ il est préférable d’insérer son code javascript à la fin d’une page plutôt que dans l’entête de celle-ci pour éviter de bloquer le téléchargement parallèle des composants de la page (car les scripts javascript sont la plupart du temps utiles une fois la page chargée mais rarement avant).

Voici donc en gros ce qu’il est préférable de faire :
avant

<html>
<head>
	  <script type="text/javascript" src="js/jquery.min.js"></script>
	  <script type="text/javascript" src="js/jquery.form.min.js"></script>
</head>
<body>
	  ... votre page ici ...
</body>
</html>

après

<html>
<head>
</head>
<body>
	  ... votre page ici ...
	  <script type="text/javascript" src="js/jquery.min.js"></script>
	  <script type="text/javascript" src="js/jquery.form.min.js"></script>
</body>
</html>

Visibilité et légèreté

Deux autres recommandations sur le JavaScript sortent du lot et sont importantes à mes yeux :

  1. Minimiser le nombre de fichiers JavaScript à inclure dans vos pages
  2. Réduire la taille des fichiers JavaScript à l’aide d’outils comme JSmin (ça les rend quasi illisibles ensuite)

Généralement un site web utilise beaucoup de scripts JavaScript provenant de frameworks comme Ext-JS, Prototype, jQuery ou MooTools mais aussi beaucoup de scripts propre à l’application qui permettent de définir le comportement des pages et les actions utilisateurs.

Voici la façon que j’utilise depuis peu pour minimiser le nombre de fichiers JavaScript selon l’environnement et la façon de les importer (à placer juste avant le </body> de votre page) :

<script type="text/javascript">
	var IN_DEV_MODE = true; // Development or Production
	var SCRIPT_URLS = []; // url scripts to import
	if (IN_DEV_MODE) {
	 	SCRIPT_URLS = [
			"js/historyKeeper/EventManager.js",
			"js/historyKeeper/History.js",
			"js/jquery.min.js",
			"js/jquery.imageMenu.js",
			"js/jquery.form.min.js",
			"js/jquery.customSelectbox.js",
			"js/votreapplication-main.js",
			"js/votreapplication-browser.js",
			"js/votreapplication-menu.js",
			"js/votreapplication-imageZoom.js"
		];
	} else {
		SCRIPT_URLS = [
   			"js/historyKeeper.all.min.js",
   			"js/jquery.all.min.js",
   			"js/votreapplication.all.min.js"
   		];
	}
	// inject js files
	for (var i=0, j=SCRIPT_URLS.length; i<j; i++) {
		document.write("<script type='text/javascript' src='" + SCRIPT_URLS[i] + "'><\/script>");
	};
</script>

Structure

Dans l’exemple ci-dessus, nous voyons que 4 fichiers sont utilisés pour notre application et injectés dans notre page (application-main, application-browser, application-menu, application-imageZoom), voici un moyen de regrouper les fonctionnalités de chacun dans un unique fichier.

Ce nouveau fichier crée un objet global JavaScript nommé App (pour Application) qui permet de définir les constantes, les méthodes et les sous objets (App.Browser, App.Menu …) afin que l’ensemble de vos petits scripts soient réunis dans un unique fichier en gardant un découpage fort.

Voici un court extrait, tiré de mon projet personnel en cours de réalisation :

/////////////////////////////////////////////////
// Main App Object
/////////////////////////////////////////////////
var App = function() {
	var ReturnObj = {
		// constants used in differents pages
		constants : {
			type : {
				quick : "quick",
				advanced : "advanced"
			}
		},
		criteria : {
			common_search : {
				sort : [], // number, power, thougness, cardtype, color, name, rarity, castingcost
				order : [] // asc, desc
                       }
		}
	};
	// init function to initialize behaviours
	var init = function() {
		App.Menu.setUp();
		App.ImageZoom.setUp();
	};
	// define functions
	ReturnObj.init = init;
	return ReturnObj;
}();
/////////////////////////////////////////////////
// Menu
/////////////////////////////////////////////////
App.Menu = function() {
	var ReturnObj = {	};
	var setUp = function() {
		$('#menu').ImageMenu({ 'extendBy':150,'saveOnClick':true,'keepOpen':false,'init':0 });
		// image positionné sur la première par défaut, donc on affiche le sous-menu correspondant
		$('#submenu ul').hide();
		$('#submenu ul:first').show();
	};
	// define functions
	ReturnObj.setUp = setUp;
	return ReturnObj;
}();
/////////////////////////////////////////////////
// Zoom image on mouseover/move
/////////////////////////////////////////////////
App.ImageZoom = function() {
	var ReturnObj = {	};
	var setUp = function() {
		// conteneur de l'image zoomée
		$("<div/>").attr({ id : 'div_zoom_image' }).css({ position : 'absolute', visibility : 'hidden', left : '-286px', top : '0px', 'z-index' : '1000' })
			.append($('<img/>').attr({ id : 'img_zoom_image' }).css({ src : '', position : 'absolute', left : '5px', top : '5px', 'z-index' : '2000' }))
			.filter('img')
		.end()
		.appendTo('body');
	};
	// affiche l'image au niveau du curseur
	var overImage = function(imgUrl) {
		alert("over");
		$('#div_zoom_image').css({ visibility : "visible" });
		$('#img_zoom_image').attr({ src : imgUrl });
		document.onmousemove = moveImage;
	};
	// masque l'image
	var outImage = function() {
		$('#div_zoom_image').css({ visibility : "hidden" });
		$('#img_zoom_image').attr({ src : '' });
		document.onmousemove = "";
	};
	// permet d'afficher l'image lorsque la souris bouge dans l'image
	var moveImage = function(event) {
		// permet de ne faire en sorte que l'image soit trop basse par rapport à la page dans le navigateur
		var cardHeight = 320;
		var dif = event.clientY + cardHeight - App.Browser.getDimensionHeight();
		var up = (dif > 0) ? dif : 0;
		// position
		var x = event.pageX + 5;
		var y = event.pageY + 5 - up;
		// placement
		document.getElementById("div_zoom_image").style.left = x + "px";
		document.getElementById("div_zoom_image").style.top = y + "px";
	};
	// define functions
	ReturnObj.setUp = setUp;
	ReturnObj.moveImage = moveImage;
	ReturnObj.outImage = outImage;
	ReturnObj.overImage = overImage;
	return ReturnObj;
}();
/////////////////////////////////////////////////
// Browser capabilities
/////////////////////////////////////////////////
App.Browser = function() {
	var ReturnObj = {	};
	// to know Browser window dimensions
	var getDimensionWidth = function() {
		if (window.innerWidth) {
			return window.innerWidth;
		} else if (document.documentElement && document.documentElement.clientWidth) {
			return document.documentElement.clientWidth;
		} else if (document.body) {
			return document.body.clientWidth;
		}
	};
	var getDimensionHeight = function() {
		if (window.innerHeight) {
			return window.innerHeight;
		} else if (document.documentElement && document.documentElement.clientHeight) {
			return document.documentElement.clientHeight;
		} else if (document.body) {
			return document.body.clientHeight;
		}
	};
	// define functions
	ReturnObj.getDimensionWidth = getDimensionWidth;
	ReturnObj.getDimensionHeight = getDimensionHeight;
	return ReturnObj;
}();

Les actions qui doivent être exécutés après le chargement complet de la page se font à présent en appelant la méthode init() de mon objet App :

<script type="text/javascript">
      App.init(); // initialize application
</script>

Conclusion

Je serai curieux de connaître votre façon de faire, que pensez-vous de celle-ci ? peut-on l’optimiser plus ?

Cet article a été écrit par :

– qui a déjà rédigé 123 posts sur Des Geeks et des lettres.

Passionné d'informatique et développeur JavaEE de métier, je me consacre principalement à écrire des billets sur les sujets du Web et de la programmation Web. Ce blog est un espace qui me permet de partager mes découvertes avec vous et me sert accessoirement de pense bête !

Contacter l'auteur

Jetez aussi un oeil sur :

{ 4 commentaires… à vous de vous exprimer ! }

1 Greg avril 1, 2010 à 13 h 16 min

Ca a l’air vraiment bien tes astuces, j’espère que les gens vont donner leurs trucs et astuces à la suite..
PS : C’est quand tu me reprogrammes complètement mon blog de A à Z ??? :D :D

Répondre

2 Mimie avril 1, 2010 à 13 h 19 min

Quand mes journées feront 48h au lieu de 24h … :D

Répondre

3 Greg avril 1, 2010 à 13 h 31 min

Arf.. c’est pas gagné

Répondre

4 Francis Levasseur juin 21, 2011 à 17 h 25 min

Bonjour, très bon code!

personnellement, je préfères minifier mon js à l’aide de php-jsmin (compilé comme un module de php5). je me suis créé un fichier php qui charge le contenu de tous mes js, les minifie puis me retourne le tout en texte.
j’ai également la possibilité de mettre en cache le résultat pour économiser mon serveur ^^
puis je n’ai plus qu’a appeler mon script avec la balise script standard.

ça me permet de travailler mon js n’importe quand, je n’ai pas à me casser les coui**es a minifier mon code a chaque changement.

Francis

Répondre

Laissez un Commentaire

Article précédent:

Article suivant: