Makina Blog
Optimiser le chargement des publicités en asynchrone
Les publicités phagocytent la bande passante, voici comment les inviter en dernier dans le chargement de votre page.
Ces petits encarts qui permettent à certains sites de subvenir à leurs besoins ralentissent souvent le chargement d'une page. La majorité des régies publicitaires fournissent un tag à inclure dans le head de la page HTML, puis appellent l'encart à travers une fonction chargée dans ce tag.
<html><head>
<script src="http://maregiepub.lol/monscript.principal.js" />
</head><body>
<header><div id="Top"><script>ChargerPub('Top');</script></header>
<main>Mon beau contenu, roi de la SEO</main>
<aside><div id="Right"><script>ChargerPub('Right');</script></aside>
</body></html>
Avec cette technique, on se retrouve à charger dès le début de la page une ressource externe, dont on ne peut prévoir le temps de chargement, puis à charger les encarts quand le navigateur "lit" (sous-entendre "parse") les scripts inline. Quand bien même les encarts chargeraient leurs images ou objets flash en asynchrone, cette technique resterait très pauvre en performances :
- évènement
onContentLoad
: 3,531s, en bleu, la page s'affiche pour l'utilisateur - évènement
onLoad
: 5,639s, en rouge, la page et ses ressources sont totalement chargées - en vert, les requêtes concernant la publicité
En essayant de placer le tag principal en bas de page, parce qu'on adopte les
bonnes pratiques, la fonction ChargerPub()
renverra des erreurs JS undefined
, logique. Du coup, on essaie de pallier le problème en tentant d'appeler cette fonction
jusqu'à ce qu'elle soit disponible :
<html><head></head><body>
<header>
<div id="Top"><script>ChargerPubAsync('Top');</script></div>
</header>
<main>Mon beau contenu, roi de la SEO</main>
<aside>
<div id="Right"><script>ChargerPubAsync('Right');</script></div>
</aside>
<script src="http://maregiepub.lol/monscript.principal.js" />
<script>
function ChargerPubAsync(param) {
var tryChargerPub = function() {
if (typeof ChargerPub == 'undefined') {
setTimeout(tryChargerPub(), 100);
}
else {
ChargerPub(param);
}
}
tryChargerPub();
}
</script>
</body></html>
Sauf que voilà, ça ne fonctionne pas, n'essayez pas non plus de placer l'attribut async
ou defer
, car si l'on regarde de plus près ce que fait la régie pub, elle utilise la fonction document.write()
à profusion, avec parfois des chargements d'autres scripts, d'où le fait qu'elle demande de placer la fonction à un endroit précis dans le HTML, celui où l'encart doit apparaître.
Comme JavaScript est très flexible, on pourrait imaginer surcharger
document.write()
, créer un buffer pour le HTML retourné, charger également
les scripts, le tout en mode récursif. Arrêtez-vous là, d'autres l'ont fait
avant vous.
Il s'agit de PostScribe, ce script fait
exactement ce qui est prévu : il crée un buffer pour récupérer tout ce que
peuvent écrire les requêtes Ajax via document.write()
et remet tout le HTML
dans un élément défini par un ID. On peut même lui donner une callback pour
exécuter des fonctions une fois que la régie pub a fini son travail.
Voila ce à quoi on arrive au niveau code :
<html><head></head><body>
<header><div id="Top"></div></header>
<main>Mon beau contenu, roi de la SEO</main>
<aside><div id="Right"></div></aside>
<div id="#nothing" class="hidden"></div>
<script src="http://cdn.lol/jquery_et_postcribe.js"/>
<script>
jQuery(function () {
postscribe('#nothing', '<scr' + 'ipt src="http://maregiepub.lol/monscript.principal.js"><\/scr' + 'ipt>', {
done: function () {
postscribe('#Top', '<sc' + 'ript language="JavaScript">ChargerPubAsync(\'Top\');</scr' + 'ipt>');
postscribe('#Right', '<sc' + 'ript language="JavaScript">ChargerPubAsync(\'Right\');</scr' + 'ipt>');
}
});
});
//-->
</script>
</body></html>
Notez que j'ai utilisé un <div id="nothing"></div>
, je m'en sers
pour que postscribe crache ce qu'il veut dedans (l'Ajax de la régie renvoie
parfois du garbage HTML).
Les performances sont bien meilleures puisque l'utilisateur peut naviguer
tranquillement pendant que les pubs se chargent, le FOUC (Flash Of Unstyled
Content) est réduit, car l'événement onContentLoad
est plus rapide :
- évènement
onContentLoad
: 1,140s (en bleu), on a divisé par deux le temps d'affichage visible de chargement de la page pour l'utilisateur - évènement
onLoad
: 5,581s (en rouge), - en vert, les requêtes concernant la publicité
Pour le reste du chargement de la page, notez que les requêtes relatives au site représentent moins de 20 requêtes, les 3/4 de la totalité des requêtes concernent la publicité (snif).
Pour en savoir plus sur l'optimisation front-end, n'hésitez pas à vous inscrire au prochain petit-déjeuner le mercredi 8 avril sur les outils du développeur front-end (Gulp, Less/Sass, Bootstrap, etc.), ou venez me rencontrer aux Drupal Developer Days à Montpellier du 10 au 19 avril.
Actualités en lien
Générer un fichier PMTiles avec Tippecanoe
Exemple de génération et d’affichage d’un jeu de tuiles vectorielles en PMTiles à partir de données publiques.
Publier une documentation VitePress sur Read The Docs
À l'origine, le site de documentation Read The Docs n'acceptait que les documentations Sphinx ou MKDocs. Depuis peu, le site laisse les mains libres pour builder sa documentation avec l'outil de son choix. Voici un exemple avec VitePress.
Créer une application en tant que composant web avec Stencil
Mise en place dans le cadre de Geotrek, cette solution permet de se passer d'une iFrame pour afficher une application dans n'importe quel site.