Introduzione
Quando inseriamo uno script in una pagina HTML, il browser deve decidere quando scaricarlo e quando eseguirlo. Questa scelta influisce direttamente su prestazioni, ordine di caricamento e comportamento della pagina. In molti casi, il vero problema non è solo distinguere tra script sincroni e asincroni, ma capire come evitare che un file JavaScript blocchi il rendering senza perdere il controllo sull’ordine di esecuzione.
In questo tutorial ci concentriamo su un sotto-argomento molto utile e pratico: l’attributo defer. È una soluzione spesso migliore rispetto a uno script sincrono tradizionale e, in diversi casi, anche più adatta di async. Vedremo come funziona, quando usarlo e come combinarlo con HTML moderno in modo pulito e prevedibile.
Codice completo
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Esempio di script defer</title>
<!--
defer: il browser scarica lo script in parallelo
ma lo esegue solo dopo aver completato il parsing dell´HTML.
L´ordine tra gli script defer viene mantenuto.
-->
<script src="menu.js" defer></script>
<script src="analytics.js" defer></script>
</head>
<body>
<header>
<h1>Demo: script defer</h1>
</header>
<main>
<button id="openMenu">Apri menu</button>
<nav id="mobileMenu" hidden>
<ul>
<li>Home</li>
<li>Servizi</li>
<li>Contatti</li>
</ul>
</nav>
</main>
<script>
// Questo script inline gira subito, quindi deve essere usato con attenzione.
// Se dipende da elementi già presenti nel DOM, conviene metterlo in fondo al body
// oppure usare defer in un file esterno.
console.log("HTML già disponibile per gli script defer.");
</script>
</body>
</html> Spiegazione
Il comportamento degli script dipende dal modo in cui il browser costruisce la pagina. Durante il parsing dell’HTML, il browser legge il documento dall’alto verso il basso. Se incontra uno script sincrono classico come <script src="file.js"></script>, in genere si ferma, scarica il file, lo esegue e poi riprende a leggere l’HTML. Questo può rallentare la visualizzazione della pagina, soprattutto se il file JavaScript è pesante o si trova su una rete lenta.
L’attributo defer cambia questo comportamento in modo molto utile:
- il browser scarica il file in parallelo mentre continua a leggere l’HTML;
- l’esecuzione avviene dopo il parsing completo del documento;
- gli script con
defermantengono l’ordine di apparizione nel documento.
Questo significa che defer è perfetto quando lo script deve lavorare sul DOM già costruito, ad esempio per agganciare eventi, inizializzare menu, slider, validazioni o componenti interattivi.
Confronto pratico tra sincrono, async e defer
- Sincrono: blocca il parsing finché il file non è scaricato ed eseguito. Utile solo in casi particolari.
- Async: scarica in parallelo e esegue appena pronto, ma senza garantire l’ordine. Ideale per script indipendenti come analytics o widget esterni.
- Defer: scarica in parallelo, esegue dopo il parsing, mantenendo l’ordine. È spesso la scelta migliore per gli script dell’applicazione.
Esempio reale: menu mobile
Immagina di avere un pulsante che apre un menu mobile. Se lo script viene eseguito troppo presto, il browser potrebbe non aver ancora creato il pulsante nel DOM. In quel caso, document.getElementById("openMenu") restituirebbe null e il codice fallirebbe.
Con defer, invece, puoi scrivere il file JavaScript sapendo che il DOM sarà già disponibile al momento dell’esecuzione:
// menu.js
const button = document.getElementById("openMenu");
const menu = document.getElementById("mobileMenu");
if (button && menu) {
button.addEventListener("click", () => {
const isHidden = menu.hasAttribute("hidden");
if (isHidden) {
menu.removeAttribute("hidden");
button.textContent = "Chiudi menu";
} else {
menu.setAttribute("hidden", "");
button.textContent = "Apri menu";
}
});
} Questo codice è semplice, leggibile e non richiede trucchi come DOMContentLoaded se il file è caricato con defer.
Perché defer è spesso la scelta più equilibrata
Molti sviluppatori usano async pensando che sia sempre la soluzione più veloce. In realtà, la velocità non è l’unico criterio. Se hai due script che dipendono l’uno dall’altro, ad esempio utils.js e app.js, con async potresti avere problemi perché l’ordine di esecuzione non è garantito. Con defer, invece, l’ordine resta stabile:
<script src="utils.js" defer></script>
<script src="app.js" defer></script> In questo caso utils.js verrà eseguito prima di app.js, anche se il download termina in momenti diversi. Questo è molto importante nei progetti reali, dove un file può definire funzioni, classi o configurazioni usate da un altro file.
Best practice
- Usa
deferper gli script dell’applicazione: è la scelta più affidabile quando il codice interagisce con il DOM. - Usa
asyncsolo per script indipendenti: ad esempio tracker, analytics, chat widget o contenuti che non dipendono dal resto della pagina. - Evita script sincroni nel
<head>se non sono strettamente necessari: possono rallentare il rendering iniziale. - Mantieni l’ordine dei file quando uno script dipende da un altro: con
deferl’ordine è rispettato, conasyncno. - Non mescolare logiche di inizializzazione fragili: se il tuo codice richiede elementi DOM già presenti, preferisci file esterni con
defero inserisci lo script in fondo albody. - Verifica la compatibilità dei componenti di terze parti: alcuni script esterni sono pensati per essere caricati con
async, altri richiedono un ordine preciso. - Organizza il codice in moduli piccoli: più il file è chiaro, più sarà facile decidere se usare sincrono, asincrono o defer.
Una buona regola pratica è questa: se lo script serve alla pagina e dipende dal DOM, usa defer. Se invece lo script è autonomo e non influenza la struttura della pagina, allora puoi valutare async.
Riepilogo
La differenza tra script sincroni e asincroni non riguarda solo la velocità, ma anche il modo in cui il browser gestisce il caricamento della pagina. Lo script sincrono blocca il parsing, async esegue appena pronto senza ordine garantito, mentre defer carica in parallelo e rimanda l’esecuzione fino a quando l’HTML è stato completamente analizzato.
Per la maggior parte dei progetti web moderni, defer è la soluzione più equilibrata per gli script principali dell’applicazione. Ti permette di evitare blocchi, mantenere l’ordine e lavorare sul DOM in modo sicuro. È una scelta semplice, pratica e molto efficace per migliorare sia la struttura del codice sia l’esperienza utente.
Approfondisci con risorse ufficiali
- MDN Web Docs — Documentazione su
<script>,asyncedefer - WHATWG HTML Standard — Specifica ufficiale del comportamento degli script in HTML
- Web.dev — Articoli sulle prestazioni del caricamento JavaScript
- Google Chrome Developers — Guide pratiche su rendering e performance
