W3docs

Eventi del ciclo di vita della pagina in JavaScript

Scopri gli eventi del ciclo di vita della pagina in JavaScript: DOMContentLoaded, load, beforeunload e unload, quando si attivano, le differenze e le alternative moderne.

Ogni pagina aperta da un browser attraversa una sequenza prevedibile di fasi: l'HTML viene analizzato, le risorse esterne vengono scaricate, l'utente interagisce e infine la pagina viene smontata. JavaScript espone questa sequenza attraverso quattro eventi del ciclo di vita della paginaDOMContentLoaded, load, beforeunload e unload. Sapere esattamente quando si attiva ciascuno permette di eseguire il codice di inizializzazione al momento più sicuro e precoce, differire le operazioni costose finché tutto è pronto e proteggere l'utente dalla perdita di dati non salvati.

Questa guida spiega il significato di ogni evento, l'ordine in cui si attivano, le insidie più comuni e le alternative moderne per gli eventi che i browser ora sconsigliano. Ogni esempio qui sotto è eseguibile — incollalo in un file HTML o aprilo nell'editor integrato.

Il ciclo di vita della pagina in sintesi

Gli eventi si attivano in un ordine fisso. I primi due avvengono mentre la pagina si carica; gli ultimi due avvengono mentre l'utente lascia la pagina:

EventoTargetQuando si attivaUso tipico
DOMContentLoadeddocumentL'HTML è stato completamente analizzato; gli script sono eseguiti; immagini/stili potrebbero essere ancora in caricamentoInizializzare l'interfaccia, aggiungere listener, interrogare il DOM
loadwindowLa pagina e tutte le sotto-risorse (immagini, fogli di stile, iframe) sono terminateLeggere le dimensioni delle immagini, eseguire codice che richiede la presenza di tutto
beforeunloadwindowL'utente sta per navigare altroveAvvisare di modifiche non salvate
unloadwindowLa pagina viene smontata (deprecato)Pulizia legacy / analytics

Un punto chiave: DOMContentLoaded è l'evento che conviene usare nella maggior parte dei casi. Si attiva molto prima di load, quindi collegare il proprio codice a esso rende la pagina interattiva prima.

Approfondimento sull'evento DOMContentLoaded

L'evento DOMContentLoaded si attiva non appena il documento HTML è stato completamente analizzato, il che di solito avviene molto prima che le immagini, i fogli di stile e altre risorse esterne siano state caricate. In questo momento l'albero del DOM è completo, quindi document.getElementById, querySelector e simili troveranno ogni elemento scritto nell'HTML.

Poiché non attende immagini o CSS, dovresti usare DOMContentLoaded ogni volta che lo script ha bisogno solo della struttura del DOM — che è il caso di gran lunga più comune.

Come gli script influenzano DOMContentLoaded

Il browser sospende l'analisi dell'HTML ogni volta che incontra un tag <script> ordinario, esegue lo script e solo allora continua. Ciò significa che DOMContentLoaded attende gli script sincroni. Ci sono due sfumature importanti:

  • <script async> viene eseguito non appena è scaricato e non blocca DOMContentLoaded.
  • <script defer> viene eseguito dopo che il documento è stato analizzato ma prima che DOMContentLoaded si attivi, nell'ordine del documento.

Se controlli la temporizzazione degli script con questi attributi, consulta scripts: async, defer per il quadro completo.

Verificare lo stato con document.readyState

Se il codice potrebbe essere eseguito dopo che il DOM è già stato analizzato (ad esempio, uno script aggiunto dinamicamente), il listener non si attiverebbe mai perché l'evento è già avvenuto. Proteggiti da questo con document.readyState:

function onReady() {
  console.log('DOM is ready, current state:', document.readyState);
}

if (document.readyState === 'loading') {
  // Still parsing — wait for the event.
  document.addEventListener('DOMContentLoaded', onReady);
} else {
  // 'interactive' or 'complete' — DOM is already ready.
  onReady();
}

readyState attraversa tre valori: "loading" durante l'analisi, "interactive" quando il DOM è pronto (è in questo momento che si attiva DOMContentLoaded), e "complete" quando tutto, incluse le risorse, è stato caricato (è in questo momento che si attiva load).

Esempio interattivo: DOMContentLoaded in azione

Per vedere DOMContentLoaded in azione, il seguente esempio aggiorna il contenuto di un elemento div non appena il documento HTML è completamente analizzato, ma prima che la pagina sia completamente caricata.

<!DOCTYPE html>
<html lang="en">
<head>
    <title>DOMContentLoaded Example</title>
</head>
<body>
    <div id="output">Waiting for DOM...</div>
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            document.getElementById('output').innerHTML = 'DOM fully loaded and parsed!'
        });
    </script>
</body>
</html>

Questo esempio può essere incollato in qualsiasi file HTML e visualizzato in un browser per osservare quanto rapidamente si attiva DOMContentLoaded rispetto al caricamento completo della pagina.

Esplorazione dell'evento load

L'evento load è essenziale per le operazioni che richiedono che l'intera pagina web sia completamente caricata, incluse tutte le risorse dipendenti come immagini e fogli di stile. Al momento dell'attivazione di load, ogni immagine ha le sue dimensioni reali, i font sono applicati e gli iframe sono caricati — quindi questo è il posto giusto per il codice che misura la pagina renderizzata.

Il compromesso riguarda la tempistica: una singola immagine di grandi dimensioni o un widget di terze parti lento ritarda load per l'intera pagina. È per questo che dovresti riservare load alle operazioni che dipendono genuinamente dalle risorse, e mantenere l'inizializzazione ordinaria su DOMContentLoaded. Per il caricamento e la gestione degli errori di singole risorse (anziché dell'intera pagina), consulta resource loading: onload and onerror.

Esempio interattivo: dimostrazione dell'evento load

Qui creiamo un esempio in cui un messaggio viene visualizzato solo dopo che tutto sulla pagina è stato completamente caricato. Come si può notare, l'evento DOMContentLoaded avviene sempre prima dell'evento load.

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Load Event Example</title>
</head>
<body>
  <div>You see first triggered event on top of the other.</div>
  <script>
    window.addEventListener('load', function() {
      const newDiv = document.createElement("div");
      newDiv.innerHTML = 'loaded event happened!'
      document.body.append(newDiv);
    });
    window.addEventListener('DOMContentLoaded', function() {
      const newDiv = document.createElement("div");
      newDiv.innerHTML = 'DOMContentLoaded event happened!'
      document.body.append(newDiv);
    });
  </script>
</body>
</html>

Copia e testa questo codice nel tuo ambiente HTML per vedere la differenza di tempistica tra DOMContentLoaded e load.

Gestione dell'evento beforeunload

L'evento beforeunload è estremamente utile per prevenire la perdita di dati, avvisando gli utenti prima che navighino verso un'altra pagina che potrebbe avere modifiche non salvate. Quando un handler imposta event.returnValue, il browser mostra una finestra di dialogo di conferma generica ("Lasciare il sito? Le modifiche apportate potrebbero non essere salvate").

Alcune regole che i browser ora applicano, da conoscere prima di affidarsi a questo:

  • Il messaggio personalizzato viene ignorato. Per evitare spam, i browser mostrano il proprio testo indipendentemente dalla stringa assegnata. È sufficiente impostare returnValue su un valore non vuoto (o chiamare event.preventDefault()) per attivare il prompt.
  • La finestra di dialogo appare solo se l'utente ha interagito con la pagina (cliccato, digitato, ecc.). Una pagina che l'utente non ha mai toccato non può bloccare la navigazione.
  • Registra il handler solo quando ci sono effettivamente modifiche non salvate, e rimuovilo una volta che i dati sono salvati. Un handler beforeunload permanente infastidisce gli utenti e può danneggiare le prestazioni della cache avanti/indietro.

Un pattern più robusto aggiunge e rimuove il listener in base a un flag di stato non salvato:

let isDirty = false;

function beforeUnloadHandler(event) {
  event.preventDefault();
  // Required for some browsers to show the dialog.
  event.returnValue = '';
}

function markDirty() {
  if (!isDirty) {
    isDirty = true;
    window.addEventListener('beforeunload', beforeUnloadHandler);
  }
}

function markSaved() {
  isDirty = false;
  window.removeEventListener('beforeunload', beforeUnloadHandler);
}

Esempio interattivo: implementazione della conferma beforeunload

Questo esempio mostra all'utente una finestra di dialogo di conferma quando tenta di lasciare la pagina, aiutando a prevenire la perdita accidentale di dati.

<!DOCTYPE html>
<html lang="en">
<head>
    <title>beforeunload Example</title>
</head>
<body>
    <p>Now if you want to exit this page, a confirmation alert will be shown as a result of the <code>beforeunload</code> event.</p>
    <script>
        window.addEventListener('beforeunload', function(event) {
            event.returnValue = '';
        });
    </script>
</body>
</html>

Testa questo codice accedendo alla pagina "prova tu stesso" e poi tentando di navigare verso un'altra pagina.

Utilizzo dell'evento unload

Attenzione

The unload event is deprecated and you won't be able to use it in most modern browsers. It is also considered a bad practice. Therefore this part is only for better information about legacy codes.

Sebbene meno comunemente usato a causa delle restrizioni dei browser moderni e dell'ascesa delle applicazioni a pagina singola, l'evento unload veniva storicamente eseguito mentre una pagina veniva smontata — utile per liberare risorse o inviare un ultimo ping di analytics. Il problema è che unload (e beforeunload) impedisce al browser di memorizzare la pagina nella cache avanti/indietro (bfcache), il che rallenta la navigazione con il pulsante Indietro per tutti.

Alternative moderne: visibilitychange e pagehide

Invece di unload, ascolta visibilitychange e tratta la transizione verso "hidden" come l'ultimo momento affidabile per persistere lo stato. Questo si attiva in modo consistente su desktop e mobile, incluso quando l'utente cambia scheda o chiude l'app:

document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'hidden') {
    // Last reliable point to save state.
    console.log('Page hidden — flush analytics / save draft here');
  }
});

Per inviare dati all'uscita, usa navigator.sendBeacon(), che mette in coda una richiesta che sopravvive alla chiusura della pagina:

function sendStats(data) {
  navigator.sendBeacon('/log', JSON.stringify(data));
}

Esempio interattivo: utilizzo dell'evento unload

Questo codice mostra un messaggio di alert quando la pagina viene scaricata. È deprecato come menzionato, e non funziona nella maggior parte dei browser moderni — preferisci visibilitychange come descritto sopra.

<!DOCTYPE html>
<html lang="en">
<head>
    <title>unload Example</title>
</head>
<body>
    <script>
        window.addEventListener('unload', function(event) {
            alert('Page is unloading...');
            // Perform cleanup tasks or analytics here
        });
    </script>
</body>
</html>

Conclusione

Ognuno di questi eventi serve una fase specifica nel ciclo di vita di una pagina web, dal caricamento iniziale allo scaricamento finale. Le indicazioni pratiche sono brevi:

  • Esegui la maggior parte dell'inizializzazione su DOMContentLoaded — si attiva prima di tutto e il DOM è pronto.
  • Usa load solo quando dipendi da immagini, font o altre sotto-risorse completamente presenti.
  • Usa beforeunload per proteggere le modifiche non salvate, e aggiungi il listener solo mentre i dati non sono ancora salvati.
  • Evita unload; usa invece visibilitychange insieme a navigator.sendBeacon().

Per approfondire, esplora questi capitoli correlati:

Esercitazione

Pratica
Cosa fa l'evento 'beforeunload' nell'esempio HTML fornito?
Cosa fa l'evento 'beforeunload' nell'esempio HTML fornito?
Was this page helpful?