Différer les scripts jusqu'à ce qu'ils soient nécessaires

Chargez le JavaScript à la demande à l'aide d'IntersectionObserver et de déclencheurs d'interaction utilisateur

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-03-05

Différer les scripts jusqu'à ce qu'ils soient nécessaires

La page mobile médiane livre 251 ko de JavaScript inutilisé selon le [url=https:\/\/almanac.httparchive.org\/en\/2025\/page-weight]Web Almanac 2025[\/url]. Il s'agit de JavaScript que le navigateur télécharge, analyse et compile avant même qu'un visiteur n'en ait besoin. Des formulaires sur lesquels personne n'a cliqué. Des widgets de chat que personne n'a ouverts. Des intégrations de cartes situées sous la ligne de flottaison. Tout cela entre en concurrence pour la bande passante et le temps CPU pendant la phase la plus critique du chargement de la page.

Le moyen le plus efficace de gérer cela est de ne charger les scripts que lorsqu'ils sont réellement nécessaires. C'est différent de l'utilisation de l'[url=\/pagespeed\/async-vs-defer-javascript-and-core-web-vitals]attribut async ou defer[\/url] sur une balise script. Ces attributs téléchargent toujours le script pendant le chargement de la page ; ils modifient simplement le moment de son exécution. Le chargement à la demande ne télécharge pas du tout le script tant qu'un déclencheur n'est pas activé.

Dernière révision par [url=https:\/\/www.linkedin.com\/in\/arjenkarel\/]Arjen Karel[\/url] en mars 2026

[include]toc.html[\/include]

Nous faisons cela avec les images depuis longtemps. C'est ce qu'on appelle le lazy loading. Avec le lazy loading, une image située sous la ligne de flottaison est chargée juste avant d'apparaître dans la fenêtre d'affichage. Le navigateur peut consacrer ses ressources au téléchargement, à l'analyse et au rendu des éléments qui sont réellement nécessaires. Le même principe s'applique au JavaScript, et cela corrigera l'[url=\/pagespeed\/reduce-unused-javascript-lighthouse]avertissement Lighthouse "réduire le JavaScript inutilisé"[\/url] et améliorera les métriques de réactivité comme l'[url=\/core-web-vitals\/interaction-to-next-paint]Interaction to Next Paint (INP)[\/url].

Malheureusement, ce n'est pas aussi simple que d'ajouter loading="lazy" à una image, mais avec une petite fonction utilitaire et un déclencheur, nous pouvons y arriver.

L'utilitaire d'injection de script

Pour ajouter des scripts à la page après son chargement, nous avons besoin d'une petite fonction qui crée un élément script et l'ajoute à l'en-tête du document.

function injectScript(scriptUrl, callback) {
    const script = document.createElement('script');
    script.src = scriptUrl;
    if (typeof callback === 'function') {
        script.onload = callback;
    }
    document.head.appendChild(script);
}

Le paramètre scriptUrl est l'URL du script à charger. La fonction optionnelle callback s'exécute une fois le chargement du script terminé. C'est important pour les scripts qui nécessitent une initialisation, comme l'appel à initMap() après le chargement de l'API Google Maps.

Déclencher le chargement à la demande

Une fois l'utilitaire d'injection en place, nous avons besoin d'un déclencheur. Il existe deux méthodes fiables : le chargement lorsqu'un élément apparaît à l'écran lors du défilement, et le chargement lorsque l'utilisateur interagit avec un élément.

IntersectionObserver : charger lorsque visible

L'IntersectionObserver se déclenche lorsqu'un élément entre dans le viewport. C'est le bon déclencheur pour les scripts liés à une section spécifique de la page : un conteneur de carte, une section de commentaires ou un widget intégré situé sous la ligne de flottaison.

function injectScriptOnIntersection(scriptUrl, elementSelector, callback) {
    const element = document.querySelector(elementSelector);
    const observer = new IntersectionObserver((entries, obs) => {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                injectScript(scriptUrl, callback);
                obs.unobserve(entry.target);
            }
        });
    });
    observer.observe(element);
}

La fonction prend l'URL du script, un sélecteur CSS pour l'élément qui doit déclencher le chargement, et un callback optionnel pour l'initialisation. Lorsque l'élément apparaît à l'écran, le script est injecté et l'observateur se déconnecte.

\/\/ Charger l'API Google Maps lorsque le conteneur de la carte apparaît au défilement
injectScriptOnIntersection(
    'https:\/\/maps.googleapis.com\/maps\/api\/js?key=VOTRE_CLE',
    '#map-container',
    () => initMap()
);

L'IntersectionObserver est supporté par tous les navigateurs modernes (95,76 % de couverture mondiale selon [url=https:\/\/caniuse.com\/intersectionobserver]Can I Use[\/url]). Aucun polyfill n'est nécessaire.

Sur interaction : charger lorsque l'utilisateur s'engage

La méthode la plus efficace consiste à ne charger un script que lorsque le visiteur interagit réellement avec l'élément qui en a besoin. Un [url=\/pagespeed\/chat-widget-perfect-core-web-vitals]widget de chat

function injectScriptOnInteraction(scriptUrl, elementSelector, eventTypes, callback) {
    const element = document.querySelector(elementSelector);
    const handler = () => {
        eventTypes.forEach(type => element.removeEventListener(type, handler));
        injectScript(scriptUrl, callback);
    };
    eventTypes.forEach(type => {
        element.addEventListener(type, handler);
    });
}

Cette fonction écoute les événements spécifiés sur l'élément cible. Au premier événement, elle supprime tous les écouteurs et injecte le script. L'avantage : si le visiteur n'interagit jamais avec l'élément, le script ne se charge jamais.

\/\/ Charger le script du widget de chat au clic ou au survol du bouton de chat
injectScriptOnInteraction(
    'chat-widget.js',
    '#chat-button',
    ['click', 'mouseover', 'touchstart'],
    () => initChat()
);

Impact concret

Ce modèle fonctionne pour tout script qui n'est pas nécessaire lors du chargement initial de la page. Quelques cas d'utilisation courants :

  • Widgets de chat : un widget de chat typique charge 200 à 400 ko de JavaScript. Lorsque Postmark a [url=https:\/\/www.patterns.dev\/vanilla\/import-on-interaction]différé son widget Intercom[\/url] pour qu'il se charge au clic plutôt que de manière immédiate, son Time to Interactive est passé de 7,7 secondes à 3,7 secondes.
  • Intégrations vidéo : une [url=\/pagespeed\/perfect-youtube-core-web-vitals]intégration YouTube[\/url] charge plus de 1 Mo de données. Affichez une vignette avec un bouton de lecture et chargez l'intégration au clic.
  • Intégrations de cartes : [url=\/pagespeed\/google-maps-100-percent-pagespeed]Google Maps[\/url] charge des centaines de kilo-octets de JavaScript. Utilisez IntersectionObserver pour le charger lorsque le conteneur de la carte apparaît à l'écran.
  • Analytics et tracking : les [url=\/pagespeed\/the-case-for-limiting-analytics-and-tracking-scripts]scripts d'analyse[\/url] peuvent attendre après la première interaction de l'utilisateur. Personne n'a jamais été déçu que son outil de heatmap commence à enregistrer 3 secondes après le chargement de la page.
  • Bibliothèques de formulaires : les bibliothèques de validation, les sélecteurs de date et les éditeurs de texte enrichi peuvent être chargés lorsque l'utilisateur se concentre sur le formulaire.

    Quand ne pas différer

    Tous les scripts ne doivent pas être différés. Si un script est responsable du rendu du contenu au-dessus de la ligne de flottaison, le différer rendra votre [url=\/core-web-vitals\/largest-contentful-paint]Largest Contentful Paint (LCP)[\/url] moins bon, et non meilleur. Les scripts qui initialisent la navigation de votre en-tête, rendent votre section hero ou mettent en place des variantes de test A\/B critiques doivent s'exécuter tôt.

    La règle est simple : si le visiteur doit voir ou interagir avec ce que le script produit dans le premier viewport, chargez-le normalement. Si le script pilote quelque chose sous la ligne de flottaison ou derrière une action de l'utilisateur, différez-le en utilisant l'un des modèles ci-dessus.

    Conseil : pour un aperçu complet de toutes les stratégies de chargement de JavaScript, consultez [url=\/pagespeed\/14-methods-to-defer-javascript]16 méthodes pour différer ou planifier le JavaScript[\/url].

    Mesurer l'amélioration

    Le [url=https:\/\/almanac.httparchive.org\/en\/2025\/performance]Web Almanac 2025[\/url] rapporte un temps de blocage total (Total Blocking Time) mobile médian de 1 916 ms, en hausse de 58 % par rapport à 2024. Une grande partie de ce blocage provient de JavaScript qui n'avait pas besoin de s'exécuter pendant le chargement de la page. En différant les scripts non critiques, vous les retirez entièrement du chemin critique.

    Après avoir mis en œuvre le chargement à la demande, vérifiez l'amélioration avec le [url=https:\/\/coredash.app]Real User Monitoring[\/url]. Vérifiez vos scores INP et le temps de blocage total dans les données de terrain, pas seulement dans Lighthouse. Les tests en laboratoire s'exécutent sur des machines rapides avec des caches vides. Vos visiteurs sont sur des réseaux mobiles avec 15 onglets de navigateur ouverts. C'est là que la différence se voit. [include]cwv\/authorbio.html[\/include]

    [include]sidebar.html[\/include] [include]blogfooter.html[\/include]
    Différer les scripts jusqu'à ce qu'ils soient nécessairesCore Web Vitals Différer les scripts jusqu'à ce qu'ils soient nécessaires