Vous avez créé votre site internet, ou votre application web, et vous souhaitez aller plus loin dans l’optimisation des temps de chargement de vos pages ?

Avec quelques outils gratuits vous allez voir qu’en revoyant un peu votre façon d’inclure votre code JavaScript, vous chargerez vos pages 2 à 3 fois plus vite.

Script de chargement asynchrone

Une chose à savoir est que les balises <script> sont bloquantes. En effet, lorsque les navigateurs téléchargent et exécutent un script JS, plus rien ne se passe. Pas de téléchargement d’image, ni de CSS, le chargement est bloqué ! Alors imaginez simplement que vous ayez 10 scripts à charger dans votre <head>, soit l’équivalent d’environ 300ko. Il y a fort à parier que le temps de charger ces 10 scripts et de les exécuter, votre page aurait eut le temps de s’afficher : HTML et CSS compris.

La première chose très facile à réaliser est de charger vos scripts juste avant la fin du <body>.

[html]
<script type="text/javascript" src="/js/jquery/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="/js/jquery/jquery.json-2.2.min.js"></script>
<script type="text/javascript" src="/js/jquery/plugins/formvalidator/jquery.validationEngine.js"></script>
</body>
</html>
[/html]

De cette façon, dans la plupart des cas HTML et CSS seront chargés avant le JavaScript. De plus, avec cette méthode, la déclaration d’un « DOM jQuery ready » devient obsolète puisque votre HTML est déja ready lorsque le JavaScript entre en action.

Franchir une nouvelle étape avec labJS

Avec labJS vous pouvez charger vos fichiers JavaScript de manière totalement asynchrone. La différence avec l’exemple précédent est que même si vous avez pris le soin de mettre vos scripts en fin de page (juste avant le </body>) ils seront tout de même téléchargés un à un.

Avec cet outil, vous pouvez charger vos scripts simultanément et spécifier un ordre d’exécution. Après quelques tests (faits avec dynaTrace), il en est ressorti que le JavaScript se chargeait 3 fois plus rapidement en utilisant labJS et que la page s’affichait 15% plus vite (sous IE8, avec 15 fichiers JS dans la page).

Un exemple :

[html]
<script src=’/js/LAB.min.js’></script>
<script>
$LAB
.script("/modules/comment/front/js/comment.js")
.script("/modules/core/commun/js/common.js")
.script("/modules/core/front/js/custom.js")
</script>

</body>
</html>
[/html]

Toutefois, il faut souligner que ce gain de vitesse est accompagné d’une légère complexification du code. Comme nous l’avons vu plus tôt les scripts sont chargés de manière asynchrone. Par conséquent certains d’entre eux seront exécutés avant d’autres; ce qui peu être mauvais lorsque vous utilisez des bibliothèques comme jQuery qui nécessitent d’être chargés avant le reste.

Deux choix s’offrent à vous : utiliser Wait() à la fin de chaque scripts qui nécessiteraient de préserver l’ordre de chargement, ou utiliser SetOptions ((AlwaysPreserveOrder:true)) qui préservera toujours votre ordre de chargement pour un coût en performance légèrement supérieur.

Voici quelques exemples d’utilisations :

Avec .Wait() :

[html]
<script src=’/js/LAB.min.js’></script>
<script>
$LAB
.script("js/jquery/jquery-1.4.2.min.js").wait()
.script("js/jquery/jquery-sortable-1.7.1.custom.min.js")
.script("js/jquery/jquery.json-2.2.min.js").wait()
.script("js/jquery/common.js")
</script>
</body>
</html>
[/html]

Avec AlwaysPreserveOrder :

[html]
<script src=’/js/LAB.min.js’></script>
<script>
$LAB
.setOptions({AlwaysPreserveOrder:true})
.script("js/jquery/jquery-1.4.2.min.js")
.script("js/jquery/jquery-sortable-1.7.1.custom.min.js")
.script("js/jquery/jquery.json-2.2.min.js")
.script("js/jquery/common.js")
</script>

</body>
</html>
[/html]

La véritable solution labJS

Pour l’ordre d’exécution nous sommes bons, mais qu’en est il de nos scripts inline ? Il faut savoir que ces bouts de script seront probablement exécutés avant même que vos fichiers JS soient téléchargés ! La solution à ce nouveau problème est efficace mais pour le coup un peu plus « compliquée » à mettre en place.

Nous allons créer une variable globale qui contiendra tous nos scripts inline. Pour ça, la première chose à faire est d’ajouter une variable dans votre <head>.

[html]
<script> var _loadingQueue = []; // declare notre tableau</script>
</head>
[/html]

Maintenant, dans n’importe quelle partie de votre page, vous pouvez ajouter un bloc de script inline, de cette façon :

[html]
<script src=’/js/LAB.min.js’></script>
<script>
_loadingQueue.push(function(){
$("body").html("this is loaded from an inline script block")
});
</script>
[/html]

Comme vous pouvez le voir j’utilise jQuery : loadingQueue.push(), qui va ajouter cette fonction anonyme à notre file d’attente de chargement. Vous pouvez en ajouter autant que bon vous semble.

Pour utiliser loadingQueue.push() dans notre séquence de chargement labJS, nous devons bricoler un peu :

[html]
<html>
<head>
<script> var _loadingQueue = []; // declare notre tableau</script>
</head>
<body>
<randomHtmlTags……………>
<script>
_loadingQueue.push(function(){
$("body").html("this is loaded from an inline script block")
});
</script>
<randomHtmlTags……………>

<script src=’/js/LAB.min.js’></script>
<script>
var $LoadDefer = $LAB
.setOptions({AlwaysPreserveOrder:true})
.script("js/jquery/jquery-1.4.2.min.js")
.script("js/jquery/jquery-sortable-1.7.1.custom.min.js")
.script("js/jquery/jquery.json-2.2.min.js")
.script("js/jquery/common.js");
.wait(function(){
framework.doSomething();
});

if( typeof( window[ ‘_loadingQueue’ ]) != "undefined"){
for(var i=0,len=_loadingQueue.length; i<len; i++){
$LoadDefer = $LoadDefer.wait(_loadingQueue[i]);
}
}
</script>
</body>
</html>
[/html]

Comme vous pouvez le voir, j’ai dû ajouter une belle boucle. Si la variable _loadingQueue existe, je reçois la longueur de _loadingQueue et quand tous les scripts sont chargés et exécutés ($LoadDefer.wait), j’exécute toutes mes fonctions stockées. Pas mal non ?

Voila donc la solution complète pour charger vos scripts de façon asynchrone. Cela devrait couvrir 99% de vos besoins.

Fusionnez et minifiez vos scripts

Lorsque vous développez en local vous ne vous en rendez pas compte, mais les requêtes que fait votre navigateur pour obtenir les fichiers connexes à votre page web, prennent du temps ! Imaginez que vous ayez 10 fichiers JS dans votre page. Si votre navigateur prend 100ms pour charger chaque fichier, vous perdez déjà 1 seconde. Il reste encore à télécharger vos images, vos CSS…

Utilisez Minify

Minify est une bibliothèque PHP qui vous permet de fusionner vos fichiers CSS et JS à la volée et les mettre en cache sur votre serveur. Avec cette bibliothèque vous pourrez récupérer cette précieuse seconde que vous avez perdu.

Minify est très simple à installer. Il suffit de le télécharger, et de le mettre à la racine de votre site. A partir de là, vous pourrez accéder simplement aux fichiers « Minifiés » comme ceci : http://www.exemple.com/min/?f=jquery/jquery-1.4.2.min.js,js/jquery/jquery-sortable-1.7.1.custom.min.js.

Peut-être vous sentirez vous un peu perdu face à la configuration de Minify. En réalité il n’y a que deux variables vraiment importantes : $min_cachPath et $min_documentRoot.

Son intégration avec labjs

Une fois que Minify fonctionne correctement :

[html]
<script src=’/js/LAB.min.js’></script>
<script>
var $LoadDefer = $LAB
.setOptions({AlwaysPreserveOrder:true})
.script("/min/?f=js/jquery/jquery-1.4.2.min.js,js/jquery/jquery-sortable-1.7.1.custom.min.js")
.script("js/jquery/common.js");

if(_loadingQueue){ for(var i=0,len=_loadingQueue.length; i<len; i++){ $LoadDefer = $LoadDefer.wait(_queue[i]) ;}}
</script>
[/html]

Petite mise en garde si vous utilisez Minify pour fusionner vos fichiers CSS ! Ce dernier peut corrompre les chemins de vos images. Si vous utilisez toujours des chemins absolus dans vos CSS, vous n’aurez pas de problème. Cependant n’oubliez pas que la plupart de vos plugins jQuery utilisent des chemins relatifs dans leur CSS !

Conclusion

Optimiser son code n’est pas toujours simple. L’optimisation ajoute une petite couche de complexité à votre application. Mais le gain en performance apporté par ces solutions justifie largement de perdre quelques minutes à complexifier un peu son code.

Si vous êtes intéressé par l’optimisation de votre JS, je vous recommande de jeter un œil à l’API de labJS et Minify. Vous y trouverez toutes les options, et des instructions plus détaillées.

Il existe d’autres technologies qu’il convient de mentionner, à savoir YUI Compressor qui peut remplacer la bibliothèque Minify, et requireJS qui peut remplacer labJS. L’approche de requireJS est différente de celle de labJS, au lieu de se concentrer sur le chargement asynchrone des fichiers, requireJS se centralise plutôt sur le chargement des fichiers qui sont réellement utilisés par votre page.