Attributi defer e async: come funzionano negli script HTML
Gli attributi defer e async funzionano permettendo al browser di scaricare un file JavaScript esterno in background senza interrompere la lettura dell'HTML, differenziandosi per il momento in cui lo script viene eseguito e per l'ordine con cui più script vengono processati.
Gli attributi defer e async sono due proprietà del tag <script> che permettono al browser di scaricare un file JavaScript esterno in background, senza interrompere la lettura dell’HTML: la differenza riguarda il momento in cui lo script viene eseguito e l’ordine con cui più script vengono processati.
Attributi defer e async in sintesi
- Download: con entrambi gli attributi lo script si scarica in parallelo, senza bloccare la lettura dell’HTML.
- Esecuzione con defer: avviene solo dopo che l’intero documento HTML è stato analizzato, prima dell’evento
DOMContentLoaded. - Esecuzione con async: parte non appena il download termina, anche a metà analisi del documento.
- Ordine: defer mantiene l’ordine di comparsa nel codice, async esegue per primo lo script che finisce di scaricarsi prima.
- Uso tipico: defer per script che dipendono dal DOM o da altri script, async per script indipendenti come strumenti di misurazione del traffico.
- Script senza src: entrambi gli attributi vengono ignorati sugli script inline classici.
Perché esistono gli attributi defer e async
Nascono per risolvere un problema strutturale del linguaggio di markup: i file JavaScript sono per natura parser-blocking, cioè bloccano l’analisi del codice HTML finché non vengono scaricati ed eseguiti. Quando il browser incontra un tag <script> privo di attributi, sospende la costruzione della pagina, richiede il file (se esterno) e ne esegue il contenuto prima di riprendere la lettura del documento.
Questo comportamento predefinito genera un ritardo visibile ogni volta che lo script è di grandi dimensioni o il server che lo ospita risponde lentamente: l’utente vede una pagina bianca o parzialmente disegnata finché il thread principale non si libera. Sui dispositivi mobili l’effetto è amplificato, perché la capacità di elaborazione è inferiore e la connessione di rete spesso più lenta rispetto a un desktop.
Gli attributi defer e async sono stati introdotti proprio per separare due fasi che di default sono vincolate insieme: il download dello script e la sua esecuzione. Entrambi consentono al parser di continuare a costruire il DOM (DOM) mentre il file si scarica in background; cambia solo il momento in cui il codice JavaScript viene effettivamente eseguito e se l’ordine tra più script viene rispettato.
La scelta tra i due non è indifferente: uno script che manipola elementi della pagina deve trovare il DOM già pronto, mentre uno script che non interagisce con il contenuto può essere eseguito appena disponibile, senza attendere nulla. Questa distinzione guida tutte le decisioni pratiche trattate nelle sezioni seguenti, incluse le tabelle di confronto e i casi limite in cui uno dei due attributi viene ignorato dal browser.
Per comprendere appieno il funzionamento di questi attributi è utile avere presente anche il comportamento dei fogli di stile, altra risorsa che può incidere sul rendering: approfondimenti correlati si trovano nella pagina dedicata a Cascading Style Sheets (CSS).
Comportamento standard senza attributi
Senza defer né async, lo script viene trattato come una risorsa sincrona: il parser HTML si ferma nel punto esatto in cui incontra il tag, scarica il file se è esterno, lo esegue integralmente e solo a quel punto riprende l’analisi del documento. Tutto ciò che nel codice segue il tag non può essere analizzato né disegnato finché questa sequenza non si conclude; il contenuto già analizzato prima dello script, invece, può essere mostrato.
Due conseguenze pratiche derivano da questo comportamento. La prima riguarda la visibilità del contenuto: se lo script sincrono è posizionato nell’<head> e richiede tempo per essere scaricato, il First Contentful Paint (FCP) viene ritardato di conseguenza. La seconda riguarda l’accesso al DOM: uno script sincrono posizionato prima di un elemento HTML non può fare riferimento a quell’elemento, perché non esiste ancora nell’albero del documento nel momento in cui lo script viene eseguito.
Una soluzione diffusa prima dell’introduzione di defer e async era spostare il tag <script> alla fine del <body>, così da far comparire prima il contenuto visibile. Il limite di questo approccio è che lo script viene scoperto più tardi: il preload scanner, il parser secondario che legge in anticipo il markup per avviare i download, lo incontra solo in fondo al documento, dopo tutte le altre risorse. Su pagine lunghe il download parte quindi più tardi rispetto a uno script con defer dichiarato nell'<head>, che viene individuato subito pur eseguendosi solo a fine parsing.
Come funziona l’attributo defer

Con l’attributo defer il browser avvia il download del file JavaScript appena incontra il tag, in parallelo con la lettura del resto del documento, ma ne rimanda l’esecuzione a un momento preciso: subito dopo che l’intero HTML è stato analizzato e poco prima che scatti l’evento DOMContentLoaded. Questo significa che lo script trova sempre il DOM completo e già pronto per essere manipolato, senza bisogno di posizionare il tag in fondo alla pagina.
Una caratteristica distintiva di defer è il rispetto dell’ordine di comparsa nel codice: se nel documento sono presenti più script con questo attributo, vengono eseguiti nella sequenza in cui sono scritti, indipendentemente da quale abbia terminato il download per primo. Uno script di piccole dimensioni collocato dopo uno script pesante dovrà quindi attendere che quest’ultimo venga eseguito, anche se il suo download si è concluso prima.
Un’altra proprietà da conoscere riguarda l’evento DOMContentLoaded: questo evento attende il completamento di tutti gli script con defer prima di attivarsi. Qualsiasi codice collegato a quell’evento, quindi, parte solo dopo che gli script differiti hanno terminato di eseguirsi, garantendo coerenza tra la logica applicativa e lo stato del DOM.
defer è la scelta indicata per tutto ciò che legge o modifica elementi della pagina, o che dipende da un altro script caricato nello stesso documento: librerie di utilità, componenti interattivi, script che inizializzano elementi dell’interfaccia. In questi casi l’ordine di esecuzione garantito evita errori dovuti a dipendenze non ancora disponibili. Va ricordato che l’attributo viene semplicemente ignorato se il tag <script> non ha un attributo src, perché si applica solo a file esterni.
Come funziona l’attributo async

Con l’attributo async il download del file avviene anch’esso in background mentre il parser continua a leggere l’HTML, ma l’esecuzione parte non appena il download è terminato, senza attendere la fine dell’analisi del documento. In quell’istante preciso il parsing viene interrotto temporaneamente per eseguire lo script, per poi riprendere subito dopo.
La conseguenza più rilevante riguarda l’ordine: tra più script con async non esiste alcuna garanzia di sequenza. Viene eseguito per primo quello che termina il download per primo, indipendentemente dalla posizione che occupa nel codice HTML. Uno script di piccole dimensioni scritto dopo uno script pesante può quindi essere eseguito prima, semplicemente perché richiede meno tempo per scaricarsi.
Per lo stesso motivo, async è indicato solo per script completamente indipendenti, che non leggono né modificano il DOM in un ordine specifico e non dipendono dal risultato di altri script presenti nella pagina. Gli esempi tipici sono gli strumenti di misurazione del traffico e i pixel di tracciamento: la loro esecuzione non deve rispettare alcuna sequenza rispetto al resto del codice della pagina.
Un dettaglio spesso trascurato riguarda la priorità di rete: nei browser basati su Chromium gli script con async, così come quelli con defer, ricevono di default una priorità di download bassa, inferiore a quella di uno script sincrono. Se è necessario che lo script si scarichi più rapidamente, senza però bloccare il parsing, è possibile aggiungere l’attributo fetchpriority=”high” allo stesso tag. Anche async, come defer, si applica solo a script esterni con attributo src e viene ignorato sugli script inline classici.
Differenze pratiche tra defer e async
Le due strategie condividono il download non bloccante, ma si separano su tre aspetti: il momento dell’esecuzione, la presenza o meno di blocco del parsing e il rispetto dell’ordine tra script multipli. La tabella seguente mette a confronto i quattro comportamenti possibili, incluso quello di uno script senza attributi.
| Caratteristica | Senza attributi | Con async | Con defer |
|---|---|---|---|
| Download | Blocca il parsing | In parallelo | In parallelo |
| Esecuzione | Immediata, blocca la pagina | Appena terminato il download | A fine parsing, prima di DOMContentLoaded |
| Blocca il parsing | Sì, per l’intera durata | Solo durante l’esecuzione | Mai |
| Ordine di esecuzione | Rispettato | Non garantito | Rispettato |
Un elemento pratico che la tabella non mostra riguarda type="module": gli script dichiarati come moduli ECMAScript ereditano automaticamente il comportamento di defer, anche senza dichiararlo esplicitamente. Se a uno script di tipo modulo viene aggiunto anche async, prevale quest’ultimo: lo script viene eseguito appena pronto, senza attendere la fine del parsing né rispettare l’ordine documentale.
Un altro aspetto da chiarire riguarda la coesistenza dei due attributi sullo stesso tag: se un <script> dichiara sia async sia defer, nei browser moderni prevale sempre async e defer viene ignorato. Questo pattern era utile come fallback per browser molto datati privi di supporto ad async, ma non ha più alcuna utilità pratica negli ambienti attuali.
Quando scegliere defer o async
La scelta corretta dipende dal tipo di dipendenza che lo script ha rispetto al DOM e agli altri script presenti nella pagina. I bivi seguenti riassumono le condizioni più frequenti.
Se lo script legge o modifica elementi della pagina: usa defer
Quando il codice deve selezionare elementi HTML, aggiungere gestori di eventi o modificare il contenuto visibile, è necessario che il DOM sia completo. In questo caso l’attributo da applicare è defer, perché garantisce l’esecuzione solo a parsing concluso.
Se lo script non dipende da nulla nella pagina: usa async
Quando il codice non legge il DOM e non richiede che altri script siano già stati eseguiti, puoi applicare async: lo script partirà appena scaricato, senza penalizzare i tempi di attesa degli altri elementi della pagina.
Se più script dipendono l’uno dall’altro: usa defer su tutti
Quando uno script richiama funzioni o variabili definite in un altro script esterno, entrambi vanno dichiarati con defer e nell’ordine corretto nel codice HTML: solo così l’esecuzione sequenziale è garantita. Applicare async in questo scenario espone al rischio di race condition, cioè errori dovuti a un ordine di esecuzione diverso da quello previsto.
Se il contenuto principale dipende interamente dal JavaScript: valuta con attenzione defer
Nelle applicazioni che costruiscono l’intero contenuto via script, l’uso di defer può ritardare il momento in cui l’elemento principale della pagina diventa visibile, perché il contenuto non compare finché lo script non viene eseguito dopo il parsing. In questo scenario conviene valutare se una parte del rendering può avvenire lato server, indipendentemente dalla strategia di caricamento dello script.
Casi particolari e limiti di defer e async
Alcuni comportamenti sfuggono alla logica generale descritta finora e riguardano situazioni tecniche specifiche, spesso fonte di errori quando non vengono considerate in fase di implementazione.
Script inline senza attributo src
Né defer né async hanno effetto su uno script inline classico, cioè privo dell’attributo src: il browser li ignora entrambi e lo script inline viene eseguito in modo sincrono, nel punto esatto in cui compare nel documento. L’unica eccezione è lo script dichiarato con type="module", che si comporta come differito anche quando è scritto direttamente nel codice HTML.
Script creati dinamicamente via JavaScript
Uno script aggiunto al documento tramite codice, ad esempio creando un elemento e collegandolo al DOM, si comporta per default come se avesse l’attributo async: non attende altri script e non viene atteso da essi, venendo eseguito secondo l’ordine di completamento del download. È possibile forzare il rispetto dell’ordine documentale impostando esplicitamente la proprietà async a false sull’elemento script prima di aggiungerlo alla pagina.
Come applicare l’attributo corretto a uno script esterno
1. Verifica che il tag abbia l’attributo src: in sua assenza, sia defer sia async vengono ignorati sugli script classici.
2. Verifica se lo script legge o modifica elementi del DOM: se sì, vai al passo 5.
3. Verifica se lo script dipende da un altro script della pagina, o se altri script dipendono da lui: se sì, vai al passo 5.
4. Se lo script non ha dipendenze dal DOM né da altri script, aggiungi l’attributo async al tag.
5. In tutti gli altri casi aggiungi l’attributo defer, applicandolo a tutti gli script collegati e mantenendo nel codice HTML l’ordine in cui devono essere eseguiti.
async a librerie da cui altri script dipendono, ad esempio una libreria di utilità condivisa: il rischio è che il codice dipendente venga eseguito prima che la libreria sia disponibile, generando errori non sempre riproducibili in fase di test. Un ambiente di sviluppo coerente con quello di pubblicazione aiuta a intercettare questi problemi prima del rilascio: per approfondire la differenza tra i contesti di sviluppo e pubblicazione consulta la pagina su ambiente di produzione nello sviluppo web e software.
Impatto di defer e async sui Core Web Vitals
La strategia di caricamento degli script incide direttamente su alcune metriche di performance monitorate per valutare l’esperienza di navigazione. Uno script sincrono danneggia il First Contentful Paint perché nessun contenuto viene disegnato finché il codice non termina di essere scaricato ed eseguito; se l’elemento principale della pagina dipende da quello script, ne risente anche il Largest Contentful Paint (LCP).
Gli script con async migliorano il tempo del primo contenuto visibile, perché il download non blocca il parsing, ma possono comunque incidere sulla reattività della pagina se vengono eseguiti proprio mentre l’utente interagisce con l’interfaccia, occupando il thread principale nel momento sbagliato: un effetto che si riflette sulla metrica Interaction to Next Paint (INP).
Gli script con defer offrono generalmente le metriche di rendering migliori, perché non interferiscono in alcun modo con la costruzione iniziale della pagina. Il compromesso riguarda le pagine il cui contenuto principale è generato interamente da JavaScript: in questi casi il differimento dell’esecuzione può ritardare la comparsa dell’elemento più pesante della pagina, incidendo sul LCP.
Secondo il Web Almanac 2025, solo il 15% delle pagine mobili supera l’audit delle risorse che bloccano il rendering, un dato che evidenzia quanto la gestione corretta di script e fogli di stile resti un’area critica per la maggior parte dei siti. Lo stesso report segnala che la pagina mobile mediana presenta un Total Blocking Time (TBT) di 1.916 millisecondi, in aumento del 58% rispetto al 2024. Il TBT è una metrica di laboratorio che misura per quanto tempo il thread principale resta occupato da task lunghi: defer e async non accorciano l’esecuzione degli script, ma permettono di spostarla fuori dalla fase critica del caricamento. Per ridurre il TBT occorre anche diminuire la quantità di JavaScript eseguito.
defer produce in genere un miglioramento misurabile del FCP, mentre differire l’esecuzione di script pubblicitari o di terze parti riduce il tempo che intercorre prima che l’utente possa effettivamente interagire con il contenuto principale della pagina. Monitorare periodicamente queste metriche, ad esempio attraverso strumenti di analisi delle prestazioni, resta il modo più affidabile per verificare l’effetto reale delle modifiche applicate agli script di una pagina. Per contestualizzare l’effetto della memorizzazione delle risorse sul tempo di caricamento complessivo, può essere utile consultare anche la pagina su page cache.
Domande frequenti su defer e async
Cos’è l’attributo defer?
È un attributo del tag <script> che fa scaricare il file in background senza bloccare il parsing dell’HTML, rimandandone l’esecuzione a dopo la fine dell’analisi del documento, prima dell’evento DOMContentLoaded, e mantenendo l’ordine di comparsa tra più script.
Cos’è l’attributo async?
È un attributo che fa scaricare lo script in parallelo con la lettura dell’HTML ed esegue il codice non appena il download termina, interrompendo momentaneamente il parsing; tra più script con questo attributo l’ordine di esecuzione non è garantito.
Qual è la differenza principale tra defer e async?
La differenza riguarda il momento dell’esecuzione e l’ordine: defer esegue lo script solo a fine parsing rispettando la sequenza nel codice, async esegue lo script appena scaricato, senza garantire alcun ordine rispetto ad altri script presenti nella pagina.
Cosa succede a uno script senza defer né async?
Il parsing dell’HTML si interrompe completamente: il browser scarica lo script, lo esegue e solo dopo riprende la lettura del documento, con un possibile ritardo visibile nella visualizzazione della pagina se lo script è pesante o lento da scaricare.
Cosa succede usando async e defer sullo stesso script?
Nei browser moderni prevale sempre l’attributo async e defer viene completamente ignorato; questa combinazione era utile solo come fallback per browser molto datati privi di supporto ad async e oggi non ha più alcuna funzione pratica.
Defer e async funzionano sugli script inline?
No, entrambi gli attributi vengono ignorati sugli script inline classici privi dell’attributo src. L’unica eccezione riguarda gli script dichiarati con type=”module”, che si comportano come differiti anche se scritti direttamente nel documento HTML.
Quando conviene usare defer invece di async?
Conviene usare defer quando lo script legge o modifica elementi del DOM, oppure dipende da un altro script della pagina: l’esecuzione garantita a fine parsing e il rispetto dell’ordine evitano errori dovuti a dipendenze non ancora disponibili.
Fonti e riferimenti
- Defer vs Async JavaScript e come questo influisce sui Core … (2025) www.corewebvitals.io