Script sincroni e asincroni in HTML: come gestire l’ordine di esecuzione

by Anastasia P.
SHARE
Script sincroni e asincroni in HTML: come gestire l’ordine di esecuzione
© Guida-HTML5.it

Introduzione

Quando inserisci uno script in una pagina HTML, non stai solo aggiungendo codice JavaScript: stai anche influenzando il modo in cui il browser costruisce la pagina, scarica le risorse e rende disponibile l’interfaccia all’utente. La differenza tra script sincroni e script asincroni è fondamentale per evitare blocchi, bug di inizializzazione e problemi di performance.

Un punto spesso trascurato, ma molto pratico, è l’ordine di esecuzione. In molti progetti il problema non è soltanto “caricare prima o dopo”, ma capire quali script devono partire in sequenza e quali invece possono essere eseguiti appena arrivano. Questo tutorial si concentra proprio su questo aspetto: come gestire correttamente l’ordine degli script in HTML usando approcci sincroni e asincroni in modo consapevole.

Vedremo un caso reale: una pagina con menu, analytics e un widget esterno. Alcuni script devono essere eseguiti in un ordine preciso, altri possono essere caricati senza bloccare il rendering. Capire questa distinzione ti aiuta a scrivere pagine più veloci e più stabili.

Codice completo

<!-- Script sincrono: viene eseguito subito e blocca il parsing dell´HTML -->
<script>
  // Configurazione iniziale disponibile prima di altri script
  window.appConfig = {
    siteName: "Demo Shop",
    enableTracking: true
  };
</script>

<!-- Script esterno caricato in modo asincrono: non blocca il rendering -->
<script async src="https://example-cdn.com/analytics.js"></script>

<!-- Script defer: scaricato in parallelo ma eseguito dopo il parsing dell´HTML -->
<script defer src="/js/menu.js"></script>
<script defer src="/js/cart.js"></script>

<main>
  <h1>Demo Shop</h1>
  <button id="openMenu">Apri menu</button>
  <div id="cartCount">Carrello: 0</div>
</main>

<script>
  // Script sincrono finale: utile solo se deve leggere elementi già presenti
  document.addEventListener("DOMContentLoaded", function () {
    const button = document.getElementById("openMenu");

    button.addEventListener("click", function () {
      alert("Menu aperto");
    });
  });
</script>

Spiegazione

Per capire il comportamento degli script, immagina il browser come un lettore che scorre il documento dall’alto verso il basso. Quando incontra uno script sincrono senza attributi speciali, si ferma, scarica ed esegue quello script, e solo dopo riprende a leggere l’HTML. Questo significa che il contenuto successivo resta in attesa.

Nel codice sopra, il primo blocco inline è sincrono. Serve a definire una configurazione globale prima che altri script possano usarla. È un caso pratico: se un file JavaScript esterno dipende da una variabile iniziale, quella variabile deve esistere prima dell’esecuzione del file.

Lo script con async viene scaricato in parallelo al parsing dell’HTML e viene eseguito appena è pronto, senza aspettare che il documento finisca di caricarsi. Questo è utile per codice indipendente, come analytics o strumenti di monitoraggio. Il vantaggio è evidente: non blocca il rendering. Lo svantaggio è altrettanto importante: non garantisce l’ordine di esecuzione rispetto ad altri script async.

Gli script con defer vengono anch’essi scaricati in parallelo, ma eseguiti solo dopo che l’HTML è stato completamente analizzato. Inoltre, i defer vengono eseguiti nell’ordine in cui compaiono nel documento. Nel nostro esempio, menu.js verrà eseguito prima di cart.js, anche se il download di uno dei due termina prima dell’altro. Questo rende defer ideale quando hai più file dipendenti tra loro.

Il blocco finale con DOMContentLoaded mostra un altro approccio comune: aspettare che il DOM sia pronto prima di accedere agli elementi della pagina. È una soluzione utile per script inline posizionati in fondo al documento, ma non sostituisce sempre defer. Se lo script è esterno e deve lavorare con altri moduli, defer resta spesso la scelta più pulita.

Vediamo i tre casi in modo sintetico:

  • Sincrono: esegue subito, blocca il parsing, utile per configurazioni iniziali o dipendenze immediate.
  • Async: scarica senza bloccare, esegue appena pronto, non garantisce ordine.
  • Defer: scarica senza bloccare, esegue dopo il parsing, mantiene l’ordine tra script defer.

Il punto chiave del nostro sotto-argomento è proprio questo: se l’ordine conta, async non è la scelta giusta. Se invece lo script è indipendente, async può essere perfetto. Se il codice dipende dal DOM o da altri file, defer è spesso la soluzione più affidabile.

Best practice

  • Usa script sincroni solo quando servono davvero: per esempio per impostare variabili globali prima del caricamento di moduli esterni.
  • Preferisci defer per i file applicativi: menu, componenti UI, validazioni, logiche che lavorano sul DOM.
  • Usa async per script indipendenti: analytics, chat widget, tag di tracking, banner esterni non critici.
  • Non affidarti ad async per script con dipendenze: due file async potrebbero eseguire in ordine diverso da quello previsto.
  • Posiziona gli script con attenzione: un inline script in alto può bloccare la pagina; se non è essenziale, spostalo in basso o rendilo deferibile.
  • Evita di manipolare il DOM prima che sia pronto: se lo script viene eseguito troppo presto, gli elementi potrebbero non esistere ancora.
  • Documenta le dipendenze: nei progetti reali, è utile indicare chiaramente quali script devono essere caricati prima di altri.

Una buona regola pratica è questa: async per ciò che è autonomo, defer per ciò che dipende dal documento o da altri script, sincrono solo per inizializzazioni immediate e controllate.

Se lavori su un sito con molte risorse esterne, prova a classificare ogni script con una domanda semplice: “Questo file può partire in qualunque momento oppure deve rispettare un ordine preciso?” La risposta ti guiderà verso la scelta corretta.

Riepilogo

La differenza tra script sincroni e asincroni non riguarda solo la velocità di caricamento, ma soprattutto il momento in cui il codice viene eseguito. Uno script sincrono interrompe il parsing dell’HTML, uno script async viene eseguito appena disponibile, mentre uno script defer mantiene l’ordine ed esegue il codice dopo la costruzione del DOM.

Se il tuo obiettivo è evitare errori di dipendenza, il concetto più importante da ricordare è questo: async non garantisce l’ordine. Per script collegati tra loro, defer è spesso la soluzione migliore. Per script indipendenti, invece, async può migliorare la reattività della pagina senza complicare la logica.

In pratica, scegliere bene tra sincrono, async e defer ti permette di scrivere HTML più pulito, JavaScript più affidabile e pagine più veloci.

Approfondisci con risorse ufficiali

  • MDN Web Docs - <script>: documentazione completa sugli attributi async e defer.
  • MDN Web Docs - DOMContentLoaded: utile per capire quando il DOM è pronto per essere manipolato.
  • WHATWG HTML Living Standard: specifica ufficiale del comportamento dei tag script in HTML.
  • Google Web.dev: guide pratiche sulle performance e sul caricamento delle risorse.

SHARE