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 :
- Minimiser le nombre de fichiers JavaScript à inclure dans vos pages
- 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 ?




Affichez votre portrait
{ 4 commentaires… à vous de vous exprimer ! }
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 ???
Quand mes journées feront 48h au lieu de 24h …
Arf.. c’est pas gagné
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