Les Performances web, pour aller plus loin

Openweb.eu.org > Articles  > Les Performances web, pour aller plus loin

Abstract

Dans Introduction à la performance web, les bases des bonnes pratiques et des enjeux de la performance web ont été posées. Cet article a pour but d’aller plus loin dans ce vaste domaine en décryptant l’affichage d’une page et les pistes pour l’accélérer.

Article

Principe du chargement d’une page

Le graphique en cascade (waterfall en anglais) permet de mieux comprendre comment une page s’affiche. Voyons un exemple réalisé avec Web Page Test qui, dans ce cas, simule un chargement d’une page :

Affichage d'une page avec Web page test

Le vocabulaire

Posons les bases du vocabulaire : ce graphique en cascade indique le chargement d’une page. Cet exemple est un premier accès (First view) : il faut tout télécharger, nous ne bénéficions pas de la mise en cache des contenus. Nous pourrons voir plus loin dans cet article les avantages cette mise en cache dans un second accès (Repeat view).

La requête DNS (DNS Lookup) permet de connaître l’adresse IP correspondant au nom de domaine demandé, ce qui permettra de s’y connecter.

La connexion initiale (Initial Connection) indique le temps pour effectuer la connexion TCP/IP afin de lancer le téléchargement de chaque fichier.

Le début de rendu (Start Render) indique le moment où le navigateur commence à effectuer son travail de rendu, après avoir téléchargé les fichiers CSS (symbolisé par la barre verticale verte sur l’image ci-dessus).

La barre bleue indique quand le document est complet (Document Complete), c’est-à-dire quand les éléments demandés pour le rendu de la page ont tous été téléchargés et rendus.

Une nuance importante : nous pourrions penser que le document est à la fin du téléchargement des éléments. Il n’en est rien : le document est considéré comme totalement chargé (fully-loaded) peu après la barre du document complet. Dans notre exemple, l’icône de favori se charge après que la page ait été rendue. Nous y reviendrons.

Le nombre d’éléments dans le DOM indique également la complexité de la page. Un DOM conséquent (supérieur à 1000 éléments) sera plus long à afficher par les navigateurs, particulièrement les moins récents comme Internet Explorer 6.

Premières observations

Même si dans notre exemple il n’y a qu’un nom de domaine, il ne peut rien se passer sur un nom de domaine avant qu’il ne soit « résolu » (en vert foncé sur l’image) : cela peut handicaper fortement le rendu d’une page si ces derniers se sur-multiplient. Il est donc aisé de comprendre pourquoi par exemple Google Page Speed recommande de minimiser les requêtes DNS à résoudre.

Néanmoins relativisons ce propos : la ligne de conduite généralement admise est la suivante : un navigateur peut effectuer six requêtes en parallèle vers un même domaine ou sous-domaine (comme par exemple Firefox 4 et Internet Explorer 9). Internet Explorer 6 et 7 par contre ne peuvent effectuer que deux requêtes simultanées vers un domaine.

A bon escient, cela peut être utilisé pour paralléliser les chargements : 2 domaines = 4 requêtes simultanées pour Internet Explorer 7.

Toujours dans l’exemple, le début de rendu de la page n’intervient pas avant le chargement des CSS et du Javascript placés dans le head… Tout comme la requête DNS bloque le téléchargement des fichiers sur un domaine, le rendu d’une page ne démarre pas avant que les éléments placés dans le head. On comprend aisément pourquoi il est conseillé de minimiser le nombre de CSS et de fichiers Javascript, et pour ces derniers de les placer en bas de page.

Comme notre exemple simule un chargement d’un site en HTML5 sous Internet Explorer, le Javascript est obligatoire dans le head.

Même si l’exemple ne comporte que très peu d’images (une dizaine) sur une page plutôt légère (3 ko), on peut constater que la partie pure du rendu des contenus par le navigateur est déjà plus longue que le temps écoulé avant le début du rendu. Sur des pages plus lourdes, plus complexes et avec plus de fichiers, cette partie augmente drastiquement. C’est pour cela que, souvent par abus de langage, on parle d’optimisation de performances web, on parle d’optimiser l’affichage Front-end (côté navigateur), ce dernier prenant en général le temps le plus conséquent.

Mise en cache avancée

L’exemple de mise en cache des contenus donné dans l’« Introduction à la performance web » était volontairement simplifié à l’extrême. Voyons un exemple plus avancé de mise en cache de contenus dits « statiques » (qui ne sont pas appelés à évoluer, images, CSS, etc.) via un fichier htaccess :

<FilesMatch "\.(js|css|gif|jpg|jpeg|png|ico)$">
Header unset Cookie
Header unset Set-Cookie

Header set Cache-Control "max-age=31536000"

header set vary  "Accept-Encoding"
header append vary "User-Agent"
header append Cache-Control "public" 

header append Connection "Keep-Alive"
header append Keep-Alive "timeout=5, max=100"

FileETag None
</FilesMatch>

Header unset Cookie et Header unset Set-Cookie permettent d’éviter la gestion des cookies pour ces fichiers statiques (qui peuvent amener des requêtes HTTP inutiles).

Header set Cache-Control "max-age=31536000" gère le contrôle du cache : les éléments sont mis en cache pour une année (le nombre correspond à une année en secondes), c’est-à-dire que le cache est valide une année durant.

header set vary "Accept-Encoding" : Cette instruction indique aux proxies de mettre en cache deux versions de la ressource : une compressée, et une non compressée. Ainsi, cela donne la possibilité aux proxies de proposer les deux versions, selon ce que l’utilisateur demande.

Les deux lignes concernant le Keep-Alive permettent d’activer les connexions persistantes, c’est-à-dire de laisser la connexion ouverte au cas où le navigateur ait d’autres requêtes (ce qui économise des requêtes TCP/IP). Attention, si cela améliore les performances pour le client, cela peut faire consommer des ressources et surcharger le serveur… Et donc impacter les performances. En général, il est recommandé de régler cette option sur un serveur de fichiers statiques.

FileETag None : nous n’utilisons pas les Etags, la mise en cache est correctement assurée par le Cache-Control.

Observons le résultat sur la même page sur une seconde consultation :

Second affichage d'une page avec Web page test

Comme nous pouvons le voir, aucun fichier précédemment mis en cache n’est retéléchargé. En résulte une économie conséquente de requêtes HTTP et de bande passante, il ne reste que la page PHP en question. Cette dernière est chargée en 304 millisecondes, et le rendu total passe de 2 secondes à 700 millisecondes (!).

D’autres pistes plus avancées

Lazy-loading

Nous l’avons vu, une bonne utilisation de la mise en cache des contenus permet de bien améliorer la performance lors d’une seconde consultation. Toutefois, il est également possible d’améliorer la première consultation en différant le chargement de certains éléments après que le document soit complet. Des sites comme Twitter ou Gmail utilisent beaucoup cette technique.

On appelle cette technique le lazy-loading (littéralement « chargement fainéant », qu’on traduira plutôt par chargement différé, ou chargement à la demande). Cela se fait via Javascript.

Exemple avec Jquery :

$(document).ready(function(){
 // ici le chargement de vos fichiers 
 // une fois la page chargée et rendue
 // exemple très simple
 $('#image_to_load').attr('src','img.gif');
 });

Ainsi, l’image ayant l’id image_to_load aura sa source chargée après le rendu de la page.

Attention : ce code est donné juste à titre d’exemple pour expliquer le principe de la méthode, il vaut mieux éviter de laisser une balise img vide.

On peut ainsi ne charger :

  • que certains types de contenus (exemple : les images contenues dans la page),
  • que les contenus à la demande (exemple : un système de recherche Javascript, qui ne sera actif que quand on utilise la recherche du site),
  • ou que les contenus visibles à l’écran, selon que l’utilisateur scrolle sur la page.

Tout cela permet de réduire le temps de chargement de la page. Observons le chargement d’une page avec un chargement différé d’une image :

Affichage d'une page avec un élément différé, avec Web page test

Web page test le confirme : l’image a bien été chargée après que le document soit rendu.

Attention : certes le gain de performances peut être important, mais ne sacrifiez pas tout aux performances. Prévoyez une solution de repli au cas où Javascript soit désactivé, sinon il pourrait y avoir perte d’information et/ou de référencement si cette technique est utilisée à mauvais escient !
Dans notre exemple, cela peut se faire via la balise noscript qui indiquera au navigateur n’ayant pas Javascript activé de charger l’image, ou via une redirection vers une version n’utilisant pas de chargement différé.

Diminution du nombre de requêtes HTTP via DATA-URL

Les Data-URL permettent de mettre du contenu directement en ligne dans vos CSS ou dans votre HTML.

Voici un exemple dans une CSS :

background:#000 url(pattern_136.gif) repeat; sera remplacé par : background:#000 url(data:image/gif;base64,R0lGODlhOAA4AIAAABUVFQAAACH5 BAAAAAAALAAAAAA4AdgAAAK/TGB5asiuYJKNrWjpxS7zoXTJ 1ZgaW3juaLay5ou2dbyjas5HOv83PvZhDtaMUbUKZ NepnH51ESnQaoNWs2WnNpr0+oF47jA8lCMNY/R5HBKnXar20c4hR6vn7v6vo8NiBRoZ4Rn+DQo p7jGl+d4l+j31XgoSBn5d6m5hVn5JtlZGLoJStrnu ZiHWspp+ijqupoiu0obaWuKS7jLu6ibChmLOdrLW PxqeVxLDCzs3Py8pzwczSoNPZ2tbc2dVgAAOw==) repeat;

(des retours à la lignes ont été ajoutés pour de simples raisons de lisibilité)

En général, le code produit est un petit peu plus lourd que l’image originale sous forme de fichier. Toutefois, cela économise une requête HTTP. Pensez à bien activer la compression GZIP ou DEFLATE pour optimiser cet équivalent textuel d’une image.

La mise en cache de ces contenus est fonction d’où ils ont été insérés : si, comme dans l’exemple, l’image est dans une CSS mise en cache, elle sera donc de facto mise en cache (en tout cas, le code correspondant). Si par contre, le contenu se situe dans une page HTML ou PHP qui n’est pas mise en cache, le code correspondant ne le sera donc pas non plus.

Attention : Les navigateurs récents comme Firefox ou Opera supportent très bien cette possibilité. Quant à Internet Explorer, il ne supporte cela qu’à partir de la version 8… Et ce dernier limite la taille de la Data-URL à 32 ko. On réservera donc cette technique aux très petites images et de préférence décoratives et non utiles à la compréhension de la page. Encore une fois il ne faut pas tout sacrifier aux performances.

Commentaires conditionnels

Les commentaires conditionnels permettent d’appliquer des règles CSS spécifiques pour certaines versions d’Internet Explorer, et ce afin de patcher son moteur de rendu parfois défaillant ou illogique.

<!--[if lte IE 7]>
    <link type="text/css" rel="stylesheet"
          href="fixes.css" />
  <![endif]-->

Il a toutefois été constaté que ces commentaires conditionnels bloquaient pendant un certain temps le téléchargement des fichiers.

Idéalement, si les performances web sont critiques pour votre projet et si vous pouvez vous passer des commentaires conditionnels, évitez de les utiliser. Toutefois une solution curieuse, mais parfaitement fonctionnelle, résout ce problème : il suffit de mettre un commentaire conditionnel vide en haut de votre source. Exemple :

<html>
<!--[if IE ]><![endif]-->

CONCLUSION

Une meilleure compréhension du mode de chargement et de construction des pages permet d’en optimiser la vitesse de chargement. Une mise en cache soignée ainsi que des chargements différés peuvent accélérer le rendu de vos pages très efficacement.

Il va de soi que cet article n’est pas exhaustif, d’autres techniques sont possibles, elles feront l’objet de probables futurs articles.

Références et outils :

À propos de cet article

  • Openweb.eu.org
  • Profil : Expert
  • Technologie : DOM
  • Thème : Qualité
  • Auteur :
  • Publié le :
  • Mise à jour : 21 mars 2014
  • 9 commentaires

Vos commentaires

  • Nicolas Chevallier Le 11 août 2011 à 20:03

     Pour la mise en cache avancée, ce système implique qu’à chaque changement d’images ou de CSS, il faut obligatoirement renommer le fichier pour que le navigateur télécharge la nouvelle version et n’utilise plus le fichier en cache. On peut profiter lors du déploiement de concaténer/minifier et renommer le fichier CSS.

     Pour les images DATA-URL, c’est vraiment anecdotique tellement c’est compliqué à mettre en oeuvre pour chaque navigateur. Par contre ce qui marche bien c’est les sprites, compatible avec l’ensemble des navigateurs.

    Voir aussi une conférence faite il y a quelques années abordant plusieurs aspects décrits dans l’article

    Nicolas Chevallier

  • Damien Le 12 août 2011 à 14:27

    J’ai réalisé une optimisation de mon site web de bricolage Brico.fr et en effet les résultats sont assez surprenants : je suis passé de 3s avant le rendu à 1s avant le rendu. Ce qui a le plus joué c’est la compression gzip et l’affichage du JS à la fin du chargement.

  • Nicolas Hoffmann Le 12 août 2011 à 15:17

    Franchement, les DATA-URL ne sont pas si compliquées que cela à mettre en œuvre : hormis IE6 et 7, tous le supportent très bien, et qq fonctions PHP permettent de le mettre en place.

    Quand à la mise en cache avancée, en effet, c’est très juste. Mais comme je l’avais indiqué dans l’article d’introduction aux performances :

    "Toutefois, si un changement devait être opéré sur une image, il est recommandé de changer le nom de l’image, afin d’éviter que la mise en cache n’empêche de voir ce changement."

    Je n’avais pas jugé bon de le réindiquer :) .

    Une autre solution (plus pour les CSS) est d’indiquer un querystring dans l’appel aux CSS, ex :

    link rel="stylesheet" href="/style/ND_new_green/ND_new_green.css ?v=4"

    En fait, ce sera ND_new_green.css ?v=4 qui sera mis en cache, ainsi, si l’on veut forcer à remettre à jour, il suffira juste de changer la querystring : ND_new_green.css ?v=5. C’est assez facile à mettre en place, et bon nombre de CMS le font très bien.

    Au plaisir,
    Nicolas

  • Nicolas Hoffmann Le 12 août 2011 à 15:22 En réponse à : Damien

    Ah, c’est très efficace, quand on voit des fichiers comme Jquery passer de 70ko à 15ko minifiés et Gzippés, on se dit que ça vaut le coup. :)

  • Gilles Gallico Le 26 décembre 2011 à 18:37

    C’est vrai qu’optimiser en termes de temps de réponse son site est primordial. A la fois d’un point de vue confort utilisateur et problématiques SEO où Google prend de plus en plus en compte ce critère. Pour ma part, pour mes différents sites, je me sers beaucoup de Yslow et Page Speed qui donnent des infos suffisamment détaillées pour qu’un néophyte comme moi puisse s’en sortir.

    Gilles Gallico

  • Vivien Blasquez Le 3 janvier 2012 à 17:11

    Bonjour, comme le dit Gilles il est vrai que les moteurs de recherche (enfin google en tout cas) fait attention au temps de chargement des pages, qui est un des critères qui fait la "qualité" d’un site web.
    De plus c’est une véritable problématique qui se pose entre la rapidité de chargement et la masse d’information transmise.
    Sur les sites et plus particulièrement sur les mobiles on doit faire attention à la vitesse de chargement de ses pages sans quoi perdre un internaute peut vite arriver.

    Vivien Blasquez

  • Denis Le 21 juillet 2012 à 18:13

    C’est vrai, depuis que nous avons mis à jour notre Hip Hop page et il charge plus rapide, a également amélioré le classement.

  • Nicolas Hoffmann Le 21 mars 2014 à 09:17

    Je m’autoréponds : pour la mise en cache, il est même plus efficace d’utiliser les possibilités du fichier htaccess, ça évitera même des problèmes avec les proxies avec ce que j’ai indiqué plus haut.

  • shavounet Le 21 mars 2014 à 09:50

    Côté serveur, je recommande aussi Varnish, un serveur de cache qui se place entre l’utilisateur et Apache. Pas évidant à maîtriser, mais super puissant. Sur des sites avec beaucoup d’images (genre e-commerce), l’utiliser sur les fichier statiques allège considérablement la charge du serveur (et c’est la configuration la plus simple) et certains temps de réaction.
    L’utiliser pour cacher l’ensemble d’un site est plus complexe, mais jouable.

Vos commentaires

modération a priori

Attention, votre message n’apparaîtra qu’après avoir été relu et approuvé.

Qui êtes-vous ?
Ajoutez votre commentaire ici

Ce champ accepte les raccourcis SPIP {{gras}} {italique} -*liste [texte->url] <quote> <code> et le code HTML <q> <del> <ins>. Pour créer des paragraphes, laissez simplement des lignes vides.

Suivre les commentaires : RSS 2.0 | Atom