Differisci gli script finché non sono necessari
Carica il JavaScript su richiesta utilizzando IntersectionObserver e i trigger di interazione dell'utente

Differisci gli script finché non sono necessari
La pagina mobile mediana invia 251 KB di JavaScript inutilizzato secondo il Web Almanac 2025. Si tratta di JavaScript che il browser scarica, analizza e compila prima ancora che il visitatore ne abbia bisogno. Moduli su cui nessuno ha cliccato. Widget di chat che nessuno ha aperto. Integrazioni di mappe posizionate below the fold. Tutto questo compete per la larghezza di banda e il tempo di CPU durante la fase più critica del caricamento della pagina.
Il modo più efficace per gestire questo problema è non caricare gli script finché non sono effettivamente necessari. Questo approccio è diverso dall'utilizzo dell'attributo async o defer su un tag script. Tali attributi scaricano comunque lo script durante il caricamento della pagina; cambiano solo il momento in cui viene eseguito. Il caricamento su richiesta, invece, non scarica affatto lo script finché non scatta un trigger.
Ultima revisione a cura di Arjen Karel nel mese di marzo 2026
Facciamo questo con le immagini da molto tempo. Si chiama lazy loading. Con il lazy loading, un'immagine below the fold viene caricata appena prima di scorrere nella visualizzazione. Il browser può dedicare le proprie risorse al download, all'analisi e al rendering degli elementi che sono effettivamente necessari. Lo stesso principio si applica a JavaScript e risolverà l'avviso di Lighthouse "riduci il JavaScript inutilizzato" migliorando le metriche di reattività come Interaction to Next Paint (INP).
Sfortunatamente non è semplice come aggiungere loading="lazy" a un'immagine, ma con una piccola funzione helper e un trigger possiamo farlo funzionare.
L'helper per l'inserimento degli script
Per aggiungere script alla pagina dopo il suo caricamento abbiamo bisogno di una piccola funzione che crei un elemento script e lo aggiunga all'head del documento.
function injectScript(scriptUrl, callback) {
const script = document.createElement('script');
script.src = scriptUrl;
if (typeof callback === 'function') {
script.onload = callback;
}
document.head.appendChild(script);
}
Il parametro scriptUrl è l'URL dello script da caricare. La funzione callback opzionale viene eseguita al termine del caricamento dello script. Questo è importante per gli script che richiedono un'inizializzazione, come chiamare initMap() dopo aver caricato l'API di Google Maps.
Attivazione del caricamento su richiesta
Con l'helper di inserimento in posizione, abbiamo bisogno di un trigger. Esistono due metodi affidabili: il caricamento quando un elemento scorre nella visualizzazione e il caricamento quando l'utente interagisce con un elemento.
IntersectionObserver: caricamento quando visibile
L'IntersectionObserver si attiva quando un elemento entra nel viewport. Questo è il trigger corretto per gli script legati a una sezione specifica della pagina: un contenitore di mappa, una sezione di commenti o un widget incorporato below the fold.
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 funzione accetta l'URL dello script, un selettore CSS per l'elemento che deve innescare il caricamento e una callback opzionale per l'inizializzazione. Quando l'elemento scorre nella visualizzazione, lo script viene inserito e l'observer si disconnette.
// Carica l'API di Google Maps quando il contenitore della mappa scorre nella visualizzazione
injectScriptOnIntersection(
'https://maps.googleapis.com/maps/api/js?key=YOUR_KEY',
'#map-container',
() => initMap()
);
IntersectionObserver è supportato in tutti i browser moderni (copertura globale del 95,76% secondo Can I Use). Non è necessario alcun polyfill.
Su interazione: caricamento quando l'utente interagisce
Il metodo più efficace consiste nel caricare uno script solo quando il visitatore interagisce effettivamente con l'elemento che ne ha bisogno. Un widget di chat non deve essere caricato finché qualcuno non clicca sul pulsante della chat. Una libreria di validazione dei moduli non deve essere caricata finché l'utente non si posiziona su un campo del modulo.
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);
});
}
Questa funzione resta in ascolto degli eventi specificati sull'elemento di destinazione. Al primo evento, rimuove tutti i listener e inserisce lo script. Il vantaggio: se il visitatore non interagisce mai con l'elemento, lo script non viene mai caricato.
// Carica lo script del widget di chat quando il pulsante della chat viene cliccato o si passa il mouse sopra
injectScriptOnInteraction(
'chat-widget.js',
'#chat-button',
['click', 'mouseover', 'touchstart'],
() => initChat()
);
Impatto nel mondo reale
Questo pattern funziona per qualsiasi script che non sia necessario durante il caricamento iniziale della pagina. Alcuni casi d'uso comuni:
- Widget di chat: Un tipico widget di chat carica da 200 a 400 KB di JavaScript. Quando Postmark ha differito il proprio widget Intercom per caricarlo al clic anziché in modo anticipato, il loro Time to Interactive è sceso da 7,7 secondi a 3,7 secondi.
- Video incorporati: Un incorporamento di YouTube carica oltre 1 MB di dati. Mostra una miniatura con un pulsante di riproduzione e carica l'incorporamento al clic.
- Integrazioni di mappe: Google Maps carica centinaia di kilobyte di JavaScript. Usa IntersectionObserver per caricarlo quando il contenitore della mappa scorre nella visualizzazione.
- Analisi e tracciamento: Gli script di analisi possono attendere la prima interazione dell'utente. Nessuno è mai rimasto deluso del fatto che il proprio strumento di heatmap abbia iniziato a registrare 3 secondi dopo il caricamento della pagina.
Quando non differire
Non tutti gli script dovrebbero essere differiti. Se uno script è responsabile del rendering di contenuti above the fold, differirlo peggiorerà il tuo Largest Contentful Paint, non lo migliorerà. Gli script che inizializzano la navigazione dell'header, renderizzano la sezione hero o impostano varianti critiche di test A/B devono essere eseguiti in anticipo.
La regola è semplice: se il visitatore vedrà o interagirà con ciò che lo script produce all'interno del primo viewport, caricalo normalmente. Se lo script gestisce qualcosa below the fold o dietro un'azione dell'utente, differiscilo utilizzando uno dei pattern precedenti.
Suggerimento: Per una panoramica completa di tutte le strategie di caricamento di JavaScript, consulta 16 metodi per differire o programmare JavaScript.
Misurare il miglioramento
Il Web Almanac 2025 riporta un Total Blocking Time mediano su mobile di 1.916 ms, in aumento del 58% rispetto al 2024. Gran parte di questo blocco deriva da JavaScript che non aveva bisogno di essere eseguito durante il caricamento della pagina. Differendo gli script non critici, li rimuovi completamente dal percorso critico.
Dopo aver implementato il caricamento su richiesta, verifica il miglioramento con il Real User Monitoring. Controlla i tuoi punteggi INP e il Total Blocking Time nei dati sul campo, non solo su Lighthouse. I test di laboratorio vengono eseguiti su macchine veloci con cache vuote. I tuoi visitatori utilizzano reti mobili con 15 schede del browser aperte. È lì che si nota la differenza.
Your Lighthouse score is not the full picture.
Lab tests run on fast hardware with a stable connection. I analyze what your actual visitors experience on real devices and real networks.
Analyze Field Data
