Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Atteint de JavaScriptite Aiguë [Cyril Durand]

Expert ASP.net Ajax et WCF, Cyril Durand parle dans son blog de point techniques sur ASP.net, ASP.net Ajax, JavaScript, WCF et .net en général. Cyril est également consultant indépendant, n'hésitez pas à le contacter pour de l'assistance sur vos projets

Actualités

  • Blog de Cyril DURAND, passionné de JavaScript, Ajax, ASP.net et tout ce qui touche au developpement Web Client-Side.

    N'hésitez pas à me contacter pour vos projets .net : architecture, accompagnement, formation, ...

    View Cyril Durand's profile on LinkedIn
    hit counters


    Expertise Commerce server et BizTalk

ASP.net 3.5 SP1 : combiner les fichiers JavaScript grace au CompositeScript du ScriptManager (ex ScriptCombining du toolkitScriptManager)

ASP.net 3.5 SP1 apporte principalement 2 nouveautés pour le ScriptManager : la combinaison de script et l'historique coté client.

Qu'est-ce que la combinaison de script ?

Lorsque l'on utilise ASP.net Ajax, nous incluons de plus en plus de fichiers JavaScript dans notre page, il n'est pas rare d'avoir besoin d'une douzaine de fichiers JavaScript par page surtout lorsque l'on utilise les Ajax toolkits. Cela pose un problème de performance. En effet, télécharger pleins de petits fichiers est généralement plus coûteux que télécharger un seul gros fichier, il est donc préférable d'avoir un seul gros fichier qui regroupe les différents petits fichiers. Malheureusement travailler sur un seul gros fichier n'est pas des plus agréables, l'application sur laquelle je travaille actuellement contient plus de 60 000 lignes de JavaScript répartis dans une 60aine de fichiers... Il est donc nécessaire d'avoir un système permettant de regrouper les différents fichiers JavaScript lors de l'exécution de l'application. C'est exactement ce que fait le ScriptCombining du ScriptManager.

Comment cela se passe ? Prenons un exemple.

Ajoutons classiquement 4 fichiers JavaScript via notre ScriptManager :

<asp:ScriptManager runat="server"> <Scripts> <asp:ScriptReference Path="~/file1.js" /> <asp:ScriptReference Path="~/file2.js" /> <asp:ScriptReference Path="~/file3.js" /> <asp:ScriptReference Path="~/file4.js" /> </Scripts> </asp:ScriptManager>

Analysons le traffic réseau avec HttpWatch

image 

On voit que notre page génère 8 requêtes :

  • La 1ère pour la page elle même
  • La 2ème pour les JavaScript propres à ASP.net 2.0
  • La 3ème pour le coeur du framework ASP.net Ajax
  • La 4ème pour la liaison ASP.net <=> ASP.net Ajax. On peut ne pas inclure ce fichier en mettant EnablePartialRendering à false au niveau du ScriptManager
  • Les 4 autres pour nos différents fichiers JavaScript.

Pour regrouper les différents fichiers JavaScript avec le ScriptManager on va utiliser la propriété CompositeScript du ScriptManager à la place de la propriété Scripts :

<asp:ScriptManager runat="server"> <CompositeScript> <Scripts> <asp:ScriptReference Path="~/file1.js" /> <asp:ScriptReference Path="~/file2.js" /> <asp:ScriptReference Path="~/file3.js" /> <asp:ScriptReference Path="~/file4.js" /> </Scripts> </CompositeScript> </asp:ScriptManager>

Après analyse on obtient :

image 

On observe que l'on ne fait plus que 5 requêtes, la dernière correspond à la combinaison de nos différents fichiers JavaScript. On observe également que l'on a transféré un petit moins de données, cela vient du fait que l'on a 3 requêtes de moins et donc 3 headers HTTP en moins.

Peux t'on combiner nos fichiers JavaScript avec les fichiers inclus par ASP.net Ajax ? Oui ! Pour cela on utilise toujours le ScriptReference mais non pas avec la propriété Path mais Name.

<asp:ScriptManager ID="ScriptManager1" runat="server"> <CompositeScript> <Scripts> <asp:ScriptReference name="MicrosoftAjax.js"/> <asp:ScriptReference name="MicrosoftAjaxWebForms.js"/> <asp:ScriptReference Path="~/file1.js" /> <asp:ScriptReference Path="~/file2.js" /> <asp:ScriptReference Path="~/file3.js" /> <asp:ScriptReference Path="~/file4.js" /> </Scripts> </CompositeScript> </asp:ScriptManager>

image

Plus que 3 requêtes ! Peux t'on diminuer à 2 requêtes ? Non ! Le premier fichier JavaScript, celui qui correspond au fonctionnement de ASP.net 2.0, n'est pas inclus via le ScriptManager, on ne peut donc pas le combiner. Pour que la combinaison de script fonctionne, il faut que le fichier soit inclus via un ScriptReference. A ma connaissance, on ne peut d'ailleurs même pas le supprimer.

Utilisation du ScriptCombining avec les fichiers JavaScript automatiquement inclus via des contrôles comme les toolkits.

Lorsque l'on inclut manuellement ces différents fichiers JavaScript, le ScriptCombining semble simple à utiliser mais peut-on s'en servir avec les fichiers JavaScript automatiquement inclut lorsque l'on utilise un control des toolkits ?

<asp:ScriptManager runat="server" /> <asp:TextBox ID="tbFirstName" runat="server" /> <ajaxToolkit:TextBoxWatermarkExtender runat="server" TargetControlID="tbFirstName" WatermarkText="Type First Name Here" />

image

On voit ici qu'on a demandé 6 fichiers JavaScript, les 3 premiers correspondent à ASP.net et ASP.net Ajax alors que les 3 derniers correspondent aux différents fichiers JavaScript requis par le TextBoxWatermark

Pour combiner tous ces fichiers JavaScript, il faut les rajouter dans le ScriptManager via la propriété CompositeScript :

<asp:ScriptManager runat="server"> <CompositeScript> <Scripts> <asp:ScriptReference name="MicrosoftAjax.js"/> <asp:ScriptReference name="MicrosoftAjaxWebForms.js"/> <asp:ScriptReference name="AjaxControlToolkit.Common.Common.js" assembly="AjaxControlToolkit"/> <asp:ScriptReference name="AjaxControlToolkit.ExtenderBase.BaseScripts.js" assembly="AjaxControlToolkit"/> <asp:ScriptReference name="AjaxControlToolkit.TextboxWatermark.TextboxWatermark.js" assembly="AjaxControlToolkit"/> </Scripts> </CompositeScript> </asp:ScriptManager>

image 

Ainsi nous n'avons plus que 2 fichiers JavaScript.

Comment connaitre les différents fichiers à inclure ?

Pour cela l'équipe ASP.net a mis en place un contrôle disponible sur Codeplex nous permettant de facilement analyser une page afin de connaître les différents fichiers JavaScript à ajouter, il s'agit du ScriptReferenceProfiler disponible à cette adresse : http://www.codeplex.com/aspnet/Release/ProjectReleases.aspx?ReleaseId=13356 

Pour l'utiliser, il faut mettre l'assembly (le fichier ScriptReferenceProfiler.dll) dans le dossier /bin de votre site web puis :

<%@ Register TagPrefix="srp" Assembly="ScriptReferenceProfiler" Namespace="ScriptReferenceProfiler" %> ... <srp:ScriptReferenceProfiler runat="server" />

Lorsque vous afficherez la page, vous aurez alors la liste des différents fichiers JavaScript à rajouter :

image

On voit que le ScriptReferenceProfiler est un contrôle bien sympathique. Bertrand Leroy a mis en ligne une vidéo présentant le ScriptCombining : Using Script Combining to improve AJAX performance

Attention, il faut bien comprendre comment cela fonctionne, le CompositeScript va combiner plusieurs fichiers JavaScript en un seul puis le mettre en cache coté client. Il faut donc utiliser les mêmes combinaisons de ScriptReference entres toutes les pages. Sans cela nous allons regrouper plusieurs fois les mêmes fichiers JavaScript dans des urls différentes. Au final nous téléchargerons plusieurs fois le même fichier JavaScript mais combinés dans des urls différentes. Si vous utilisez mal le ScriptCombining vous risquez d'avoir des perfs moins bonnes qu'en ne l'utilisant pas.

Peux t'on encore optimiser le chargement des fichiers JavaScript ? Oui !

Par défaut le ScriptManager envoie tous les fichiers en gzip. Cela veut dire qu'au lieu d'envoyer le texte brut au client, ASP.net l'envoie compressé en gzip, le client se charge alors de le décompresser. On voit sur les différentes captures que cela nous fait gagner de nombreux octets. De plus le ScriptManager ajoute automatiquement les en-têtes HTTP pour mettre en cache côté client les différents fichiers JavaScript. Il s'agit d'une très bonne chose !

Malgré tout, on peut encore optimiser tout cela. Puisque nous sommes de bons développeurs nos fichiers JavaScript possèdent de nombreux commentaires et espace/saut de lignes inutiles, ces éléments prennent de la place et sont nullement nécessaire pour le client.

J'ai essayé différentes options mais le ScriptManager ne permet pas de supprimer automatiquement les différents éléments inutiles des fichiers JavaScript :

image

Bien sûr il existe de nombreux outils permettant de supprimer les commentaires inutiles : jsmin est celui que j'utilise.

Pourquoi le ScriptManager ne le fait pas automatiquement ? Aucune idée ! Il s'agit d'un énorme manque et c'est une fonctionnalité nécessaire ! A cause de ce manque je vais continuer à utiliser mon système de "Script Combining".

L'autre manque du CompositeScript est l'impossibilité de créer des groupes de regroupement. Imagions que vous ayez un site où toutes vos pages utilisent file1.js ainsi que file2.js, quelques une de vos pages utilisent en plus file3.js et file4.js. Il serait bon de pouvoir regrouper file1.js avec file2.js et file3.js avec file4.js dans 2 urls distincts, ce n'est malheureusement pas possible.
Pour moi la syntaxe logique serait de passer par le ScriptManagerProxy, ou alors modifier la propriété CompositeScript pour prendre en compte une List<List<ScriptReference>> et non pas une List<ScriptReference> comme c'est le cas actuellement.

Qu'en pensez-vous ?

Avez-vous des suppositions sur l'absence de compactage et de la création des groupes ? Un simple "oubli" de la part de Microsoft ?

Bref, cette nouveauté est une nouveauté nécessaire et bien pensée, sans compactage des fichiers JavaScript on ne peut malheureusement pas utiliser cette nouveauté ! 

Et vous ? Utilisez-vous déjà cette nouveauté ? Pensez-vous l'utiliser ? Que pensez-vous de cet ajout ?


Pour les curieux : j'utilise HttpWatch afin d'analyser le trafic réseau, il s'agit d'un plugin à IE qui permet d'indiquer de nombreuses choses ! Il a de loin détrôner Fiddler.

Posted: jeudi 28 août 2008 22:39 par cyril
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Commentaires

Benjiiim a dit :

Très interessant.

Par contre, j'ai une question pas directement lié: Que fais-tu dans tes 60 000 lignes .js ???!!!

# août 28, 2008 23:26

cyril a dit :

L'appli utilise :

 - ASP.net Ajax core : ~7000 lignes

 - extjs : ~35 000 lignes - 2 fichiers

 - openlayers : ~18 000 lignes - 1 fichier

 - une surcouche à openlayers : ~9 500 lignes - 43 fichiers

 - un peu de code pour notre appli : ~4 500 lignes - 38 fichiers

oups ca fait 74 000 lignes dans 84 fichiers et l'appli n'est pas terminé... ~1.5Mo de js non gzipé, ~450ko gzippé. Tu savais pas que j'étais un psychopathe du js ? :-)

De toute façon c'est bien connu ce qui prend le plus de place dans notre code c'est les commentaires ... ;)

De mémoire je gagne 20% en supprimant espace inutile + commentaire. Tu vois maintenant pourquoi j'ai besoin d'une telle fonctionnalité et pourquoi l'absence de compactage JavaScript sur un truc assez bien foutu me laisse un peu sur ma faim.

# août 29, 2008 00:17

Benjiiim a dit :

Merci pour les détails ! :-)

Je suis rassuré, les 74 000 lignes ne sont pas toutes de toi juste pour ce projet ! :p

# août 29, 2008 00:25

Danuz a dit :

Excellent billet! Merci Cyril !

# août 29, 2008 09:01

FREMYCOMPANY a dit :

La seule chose que je me demande, c'est : garde-t-on une mise en cache des scripts avec ce système ? Le script changeant à chaque page, cela me semble difficile. Y gagne-t-on dès lors vraiment en vitesse de navigation ?

# août 29, 2008 10:39

cyril a dit :

Fremy, relis le billet je parle de ce problème ! Il faut évidemment faire en sorte que les groupes de ScriptReference du CombineScript soit les mêmes entres les pages.

# août 29, 2008 10:43

FREMYCOMPANY a dit :

@cyril : Oui, mais l'URL cliente du super-script est-elle la même ? Même si tu choisis les mêmes scripts à chaque fois, la mise en cache est-elle possible ? (Vu ta réponse, je suppose que oui, mais je me posais la question)

# août 29, 2008 21:46

cyril a dit :

l'url est généré à partir du groupe des fichiers à inclure.

file1.js + file2.js + file3.js = constante

file1.js + file2.js = autre constante

# août 30, 2008 11:33
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Etes-vous yOS compatible ? (2/3) : la nouvelle plateforme Yammer–Office 365–SharePoint par Le blog de Patrick [MVP SharePoint] le 04-22-2014, 09:27

- [ #Yammer ] [ #Office365 ] Quelques précisions sur l’activation de Yammer Entreprise par Le blog de Patrick [MVP SharePoint] le 04-22-2014, 09:03

- Après Montréal, ce sera Barcelone, rendez-vous à la European SharePoint Conference 2014 ! par Le blog de Patrick [MVP SharePoint] le 04-19-2014, 09:21

- Emportez votre sélection de la MSDN dans la poche ? par Blog de Jérémy Jeanson le 04-17-2014, 22:24

- [ #Office365 ] Pb de connexion du flux Yammer ajouté à un site SharePoint par Le blog de Patrick [MVP SharePoint] le 04-17-2014, 17:03

- NFluent & Data Annotations : coder ses propres assertions par Fathi Bellahcene le 04-17-2014, 16:54

- Installer un site ASP.net 32bits sur un serveur exécutant SharePoint 2013 par Blog de Jérémy Jeanson le 04-17-2014, 06:34

- [ SharePoint Summit Montréal 2014 ] Tests de montée en charge SharePoint par Le blog de Patrick [MVP SharePoint] le 04-16-2014, 20:44

- [ SharePoint Summit Montréal 2014 ] Bâtir un site web public avec Office 365 par Le blog de Patrick [MVP SharePoint] le 04-16-2014, 18:30

- Kinect + Speech Recognition + Eedomus = Dommy par Aurélien GALTIER le 04-16-2014, 17:17