Optimiser le code JavaScript tiers

Les scripts tiers ont un impact sur les performances. C'est pourquoi il est important de les examiner régulièrement et d'utiliser des techniques de chargement efficaces. Cet atelier de programmation vous explique comment optimiser le chargement de ressources tierces. Il aborde les techniques suivantes:

  • Différer le chargement du script

  • Chargement différé des ressources non critiques

  • Préconnexion aux origines requises

L'application exemple incluse comporte une page Web simple avec trois fonctionnalités provenant de sources tierces:

  • Intégration d'une vidéo

  • Bibliothèque de visualisation des données pour afficher un graphique en courbes

  • Un widget de partage sur les réseaux sociaux

Capture d'écran de la page avec les ressources tierces mises en évidence.
Ressources tierces dans l'application exemple.

Vous commencerez par mesurer les performances de l'application, puis appliquerez chaque technique pour améliorer différents aspects de ses performances.

Évaluer les performances

Ouvrez d'abord l'application exemple en plein écran:

  1. Cliquez sur Remixer pour modifier pour rendre le projet modifiable.
  2. Pour prévisualiser le site, appuyez sur Afficher l'application, puis sur Plein écran plein écran.

Effectuez un audit de performances Lighthouse sur la page pour établir les performances de référence:

  1. Appuyez sur Ctrl+Maj+J (ou Cmd+Option+J sur Mac) pour ouvrir DevTools.
  2. Cliquez sur l'onglet Lighthouse (Phare).
  3. Cliquez sur Mobile.
  4. Cochez la case Performances. (Vous pouvez décocher les autres cases de la section "Audits".)
  5. Cliquez sur Connexion 3G rapide simulée, processeur 4 fois plus lent.
  6. Cochez la case Effacer l'espace de stockage.
  7. Cliquez sur Effectuer des audits.

Lorsque vous exécutez un audit sur votre machine, les résultats exacts peuvent varier, mais vous devriez remarquer que le temps de First Contentful Paint (FCP) est assez élevé et que Lighthouse suggère deux possibilités d'investigation: Éliminer les ressources bloquant le rendu et Preconnecter aux origines requises. (Même si toutes les métriques sont vertes, les optimisations apporteront des améliorations.)

Capture d'écran de l'audit Lighthouse montrant un FCP de 2,4 secondes et deux opportunités : "Éliminer les ressources bloquant le rendu" et "Établir des préconnexions aux origines requises".

Différer le code JavaScript tiers

L'audit Éliminer les ressources bloquant l'affichage a révélé que vous pouvez gagner du temps en différant un script provenant de d3js.org:

Capture d'écran de l'audit "Éliminer les ressources qui bloquent l'affichage" avec le script d3.v3.min.js mis en surbrillance.

D3.js est une bibliothèque JavaScript permettant de créer des visualisations de données. Le fichier script.js de l'application exemple utilise des fonctions utilitaires D3 pour créer le graphique en courbes SVG et l'ajouter à la page. L'ordre des opérations est important ici: script.js doit s'exécuter après l'analyse du document et le chargement de la bibliothèque D3. C'est pourquoi il est inclus juste avant la balise </body> de fermeture dans index.html.

Toutefois, le script D3 est inclus dans le <head> de la page, ce qui bloque l'analyse du reste du document:

Capture d&#39;écran de l&#39;index.html avec la balise de script mise en évidence dans l&#39;en-tête.

Deux attributs magiques peuvent débloquer l'analyseur lorsqu'ils sont ajoutés à la balise de script:

  • async garantit que les scripts sont téléchargés en arrière-plan et exécutés à la première occasion une fois le téléchargement terminé.

  • defer garantit que les scripts sont téléchargés en arrière-plan et exécutés après l'analyse.

Étant donné que ce graphique n'est pas vraiment essentiel à la page globale et qu'il se trouvera probablement en dessous de la ligne de flottaison, utilisez defer pour vous assurer qu'aucun blocage de l'analyseur n'est effectué.

Étape 1: Chargez le script de manière asynchrone avec l'attribut defer

Sur la ligne 17 de index.html, ajoutez l'attribut defer à l'élément <script>:

<script src="https://d3js.org/d3.v3.min.js" defer></script>

Étape 2: Vérifier l'ordre correct des opérations

Maintenant que D3 est différé, script.js s'exécute avant que D3 ne soit prêt, ce qui entraîne une erreur.

Les scripts avec l'attribut defer s'exécutent dans l'ordre dans lequel ils ont été spécifiés. Pour vous assurer que script.js est exécuté après que D3 est prêt, ajoutez-y defer et déplacez-le vers le haut, dans la section <head> du document, juste après l'élément <script> D3. Il ne bloque plus l'analyseur, et le téléchargement commence plus tôt.

<script src="https://d3js.org/d3.v3.min.js" defer></script>
<script src="./script.js" defer></script>

Charger de façon différée des ressources tierces

Toutes les ressources situées en dessous de la ligne de flottaison sont de bons candidats pour le chargement différé.

L'application exemple comporte une vidéo YouTube intégrée dans un iFrame. Pour vérifier le nombre de requêtes effectuées par la page et celles qui proviennent de l'iFrame YouTube intégrée:

  1. Pour prévisualiser le site, appuyez sur Afficher l'application, puis sur Plein écran plein écran.
  2. Appuyez sur Ctrl+Maj+J (ou Cmd+Option+J sur Mac) pour ouvrir DevTools.
  3. Cliquez sur l'onglet Réseau.
  4. Cochez la case Disable cache (Désactiver le cache).
  5. Sélectionnez 3G rapide dans le menu déroulant Limitation.
  6. Actualisez la page.

Capture d&#39;écran du panneau &quot;Network&quot; (Réseau) de DevTools.

Le panneau Network (Réseau) indique que la page a effectué un total de 28 requêtes et transféré près de 1 Mo de ressources compressées.

Pour identifier les requêtes envoyées par le iframe YouTube, recherchez l'ID de la vidéo 6lfaiXM6waw dans la colonne Initiateur. Pour regrouper toutes les demandes par domaine:

  • Dans le panneau Réseau, effectuez un clic droit sur un titre de colonne.

  • Dans le menu déroulant, sélectionnez la colonne Domains (Domaines).

  • Pour trier les requêtes par domaine, cliquez sur l'en-tête de la colonne Domains (Domaines).

Le nouveau tri révèle qu'il existe des requêtes supplémentaires adressées aux domaines Google. Au total, l'iFrame YouTube effectue 14 requêtes pour les scripts, les feuilles de style, les images et les polices. Toutefois, à moins que les utilisateurs ne fassent défiler l'écran pour lire la vidéo, ils n'ont pas vraiment besoin de tous ces éléments.

En attendant de charger la vidéo de manière différée jusqu'à ce qu'un utilisateur fasse défiler la page jusqu'à cette section, vous réduisez le nombre de requêtes envoyées par la page au départ. Cette approche permet d'économiser les données des utilisateurs et d'accélérer la charge initiale.

Une façon d'implémenter le chargement différé consiste à utiliser Intersection Observer, une API de navigateur qui vous avertit lorsqu'un élément entre ou sort de la fenêtre d'affichage du navigateur.

Étape 1: Empêcher le chargement initial de la vidéo

Pour charger de manière différée l'iframe vidéo, vous devez d'abord l'empêcher de se charger de la manière habituelle. Pour ce faire, remplacez l'attribut src par l'attribut data-src afin de spécifier l'URL de la vidéo:

<iframe width="560" height="315" data-src="https://www.youtube.com/embed/lS9D6w1GzGY" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

data-src est un attribut de données qui vous permet de stocker des informations supplémentaires sur les éléments HTML standards. Vous pouvez donner n'importe quel nom à un attribut de données, à condition qu'il commence par "data-".

Un iframe sans src ne se charge tout simplement pas.

Étape 2: Utiliser Intersection Observer pour charger la vidéo de manière différée

Pour charger la vidéo lorsqu'un utilisateur y fait défiler la page, vous devez savoir quand cela se produit. C'est là qu'intervient l'API Intersection Observer. L'API Intersection Observer vous permet d'enregistrer une fonction de rappel qui est exécutée chaque fois qu'un élément que vous souhaitez suivre entre ou sort du viewport.

Pour commencer, créez un fichier et nommez-le lazy-load.js:

  • Cliquez sur Nouveau fichier et donnez-lui un nom.
  • Cliquez sur Ajouter ce fichier.

Ajoutez la balise de script à l'en-tête de votre document:

 <script src="/lazy-load.js" defer></script>

Dans lazy-load.js, créez un IntersectionObserver et transmettez-lui une fonction de rappel à exécuter:

// create a new Intersection Observer
let observer = new IntersectionObserver(callback);

Indiquez maintenant à observer un élément cible à regarder (l'iframe vidéo dans ce cas) en le transmettant en tant qu'argument dans la méthode observe:

// the element that you want to watch
const element = document.querySelector('iframe');

// register the element with the observe method
observer.observe(element);

callback reçoit une liste d'objets IntersectionObserverEntry et l'objet IntersectionObserver lui-même. Chaque entrée contient un élément target et des propriétés qui décrivent ses dimensions, sa position, l'heure à laquelle il est entré dans le viewport, etc. L'une des propriétés de IntersectionObserverEntry est isIntersecting, une valeur booléenne qui est égale à true lorsque l'élément entre dans la fenêtre d'affichage.

Dans cet exemple, target correspond à iframe. isIntersecting est égal à true lorsque target entre dans la fenêtre d'affichage. Pour voir comment cela fonctionne, remplacez callback par la fonction suivante:

let observer = new IntersectionObserver(callback);
let observer = new IntersectionObserver(function(entries, observer) {
    entries.forEach(entry => {
      console.log(entry.target);
      console.log(entry.isIntersecting);
    });
  });
  1. Pour prévisualiser le site, appuyez sur Afficher l'application, puis sur Plein écran plein écran.
  2. Appuyez sur Ctrl+Maj+J (ou Cmd+Option+J sur Mac) pour ouvrir DevTools.
  3. Cliquez sur l'onglet Console.

Essayez de faire défiler l'écran vers le haut et vers le bas. La valeur de isIntersecting devrait changer, et l'élément cible devrait être enregistré dans la console.

Pour charger la vidéo lorsque l'utilisateur fait défiler la page jusqu'à sa position, utilisez isIntersecting comme condition pour exécuter une fonction loadElement, qui récupère la valeur de l'élément data-src de l'élément iframe et la définit comme attribut src de l'élément iframe. Ce remplacement déclenche le chargement de la vidéo. Ensuite, une fois la vidéo chargée, appelez la méthode unobserve sur observer pour arrêter de surveiller l'élément cible:

let observer = new IntersectionObserver(function (entries, observer) {
  entries.forEach(entry => {
    console.log(entry.target);
    console.log(entry.isIntersecting);
  });
});
    if (entry.isIntersecting) {
      // do this when the element enters the viewport
      loadElement(entry.target);
      // stop watching
      observer.unobserve(entry.target);
    }
  });
});

function loadElement(element) {
  const src = element.getAttribute('data-src');
  element.src = src;
}

Étape 3: Réévaluer les performances

Pour voir comment la taille et le nombre de ressources ont changé, ouvrez le panneau Network (Réseau) des outils pour les développeurs, puis actualisez à nouveau la page. Le panneau Network (Réseau) indique que la page a effectué 14 requêtes et seulement 260 ko. C'est une amélioration significative !

Faites défiler la page vers le bas et observez le panneau Network (Réseau). Lorsque vous accédez à la vidéo, la page devrait déclencher des requêtes supplémentaires.

Connectez-vous à l'avance aux origines requises

Vous avez différé le code JavaScript non critique et chargé les requêtes YouTube de manière lazy-loading. Il est maintenant temps d'optimiser le reste du contenu tiers.

Ajouter l'attribut rel=preconnect à un lien indique au navigateur d'établir une connexion à un domaine avant d'effectuer la requête pour cette ressource. Cet attribut est particulièrement utile pour les origines qui fournissent des ressources dont vous êtes certain que la page a besoin.

L'audit Lighthouse que vous avez effectué à la première étape, dans la section Preconnect to required origins (Préconnecter aux origines requises), vous a suggéré que vous pouviez économiser environ 400 ms en établissant des connexions anticipées à staticxx.facebook.com et youtube.com:

Audit de la préconnexion aux origines requises avec le domaine staticxx.facebook.com mis en surbrillance

Étant donné que la vidéo YouTube est désormais chargée de manière différée, il ne reste que staticxx.facebook.com, la source du widget de partage sur les réseaux sociaux. Pour établir une connexion anticipée à ce domaine, il vous suffit d'ajouter une balise <link> à l'<head> du document:

  <link rel="preconnect" href="https://staticxx.facebook.com">

Réévaluer les performances

Voici l'état de la page après optimisation. Suivez les étapes de la section Mesurer les performances de l'atelier de programmation pour effectuer un autre audit Lighthouse.

Audit Lighthouse montrant un FCP de 1 seconde et un score de performances de 99.