API Page Lifecycle

Supporto dei browser

  • Chrome: 68.
  • Edge: 79.
  • Firefox: non supportato.
  • Safari: non supportato.

I browser moderni a volte sospendono le pagine o le ignorano del tutto quando le risorse di sistema sono limitate. In futuro, i browser vorranno eseguire questa operazione in modo proattivo, in modo da consumare meno energia e memoria. L'API Page Lifecycle fornisce hook di ciclo di vita in modo che le tue pagine possano gestire in sicurezza questi interventi del browser senza influire sull'esperienza utente. Dai un'occhiata all'API per vedere se devi implementare queste funzionalità nella tua applicazione.

Sfondo

Il ciclo di vita delle applicazioni è un modo fondamentale in cui i sistemi operativi moderni gestiscono le risorse. Su Android, iOS e versioni recenti di Windows, le app possono essere avviate e interrotte in qualsiasi momento dal sistema operativo. In questo modo, queste piattaforme possono semplificare e riallocare le risorse dove sono più utili per l'utente.

Sul web, storicamente, non è stato previsto un ciclo di vita simile e le app possono essere mantenute attive a tempo indeterminato. Con un numero elevato di pagine web in esecuzione, le risorse di sistema critiche come memoria, CPU, batteria e rete possono essere sovrascritte, con conseguente esperienza utente negativa.

Sebbene la piattaforma web abbia da tempo eventi correlati agli stati del ciclo di vita, come load, unload e visibilitychange, questi eventi consentono agli sviluppatori di rispondere solo alle modifiche dello stato del ciclo di vita avviate dall'utente. Affinché il web funzioni in modo affidabile su dispositivi a bassa potenza (e sia più attento alle risorse in generale su tutte le piattaforme), i browser devono avere un modo per recuperare e riallocare in modo proattivo le risorse di sistema.

Infatti, oggi i browser adottano già misure attive per risparmiare risorse per le pagine nelle schede in background e molti browser (in particolare Chrome) vorrebbero fare molto di più per ridurre l'impronta complessiva delle risorse.

Il problema è che gli sviluppatori non hanno modo di prepararsi a questi tipi di interventi avviati dal sistema o di sapere nemmeno che si stanno verificando. Ciò significa che i browser devono essere prudenti per non rischiare di danneggiare le pagine web.

L'API Page Lifecycle cerca di risolvere questo problema nel seguente modo:

  • Introduzione e standardizzazione del concetto di stati del ciclo di vita sul web.
  • Definizione di nuovi stati avviati dal sistema che consentono ai browser di limitare le risorse che possono essere utilizzate dalle schede nascoste o non attive.
  • Creazione di nuove API ed eventi che consentano agli sviluppatori web di rispondere alle transizioni verso e da questi nuovi stati avviati dal sistema.

Questa soluzione offre la prevedibilità necessaria agli sviluppatori web per creare applicazioni resilienti agli interventi di sistema e consente ai browser di ottimizzare in modo più aggressivo le risorse di sistema, a vantaggio di tutti gli utenti web.

Nel resto di questo post verranno presentate le nuove funzionalità del ciclo di vita della pagina e verrà spiegato il loro rapporto con tutti gli stati e gli eventi esistenti della piattaforma web. Fornirà inoltre consigli e best practice per i tipi di attività che gli sviluppatori devono (e non devono) svolgere in ogni stato.

Panoramica degli stati e degli eventi del ciclo di vita della pagina

Tutti gli stati del ciclo di vita della pagina sono discreti e mutuamente esclusivi, il che significa che una pagina può essere in un solo stato alla volta. Inoltre, la maggior parte delle modifiche allo stato del ciclo di vita di una pagina è generalmente osservabile tramite gli eventi DOM (consulta i consigli per gli sviluppatori per ogni stato per le eccezioni).

Forse il modo più semplice per spiegare gli stati del ciclo di vita della pagina, nonché gli eventi che segnalano le transizioni tra di essi, è con un diagramma:

Una rappresentazione visiva dello stato e del flusso di eventi descritti in questo documento.
Flusso di stato ed eventi dell'API Page Lifecycle.

Stati

La tabella seguente illustra in dettaglio ogni stato. Vengono elencati anche i possibili stati che possono precedere e seguire l'evento, nonché gli eventi che gli sviluppatori possono utilizzare per osservare le modifiche.

Stato Descrizione
Attivi

Una pagina è nello stato attivo se è visibile e ha il focus sull'input.

Possibili stati precedenti:
passive (tramite l'evento focus)
frozen (tramite l'evento resume, poi l'evento pageshow)

Possibili stati successivi:
passive (tramite l'evento blur)

Passiva

Una pagina è in stato passivo se è visibile e non ha il focus di immissione.

Possibili stati precedenti:
attivo (tramite l'evento blur)
nascosto (tramite l'evento visibilitychange)
congelato (tramite l'evento resume, poi l'evento pageshow)

Possibili stati successivi:
attivo (tramite l'evento focus)
nascosto (tramite l'evento visibilitychange)

Nascosto

Una pagina è in stato nascosto se non è visibile (e non è stata bloccata, eliminata o interrotta).

Possibili stati precedenti:
passive (tramite l'evento visibilitychange)
frozen (tramite l'evento resume, poi l'evento pageshow)

Possibili stati successivi:
passive (tramite l'evento visibilitychange)
frozen (tramite l'evento freeze)
discarded (nessun evento attivato)
terminated (nessun evento attivato)

Congelato

Nello stato congelato, il browser sospende l'esecuzione delle attività bloccabili nelle code di attività della pagina fino a quando la pagina non viene scongelata. Ciò significa che elementi come i timer e i callback di recupero di JavaScript non vengono eseguiti. Le attività già in esecuzione possono essere completate (in particolare il callback freeze), ma potrebbero essere limitate in termini di ciò che possono fare e di quanto tempo possono essere eseguite.

I browser bloccano le pagine per preservare l'utilizzo di CPU/batteria/dati. Lo fanno anche per consentire navigate avanti/indietro più rapide, evitando la necessità di ricaricare completamente la pagina.

Possibili stati precedenti:
hidden (tramite l'evento freeze)

Possibili stati successivi:
attivo (tramite l'evento resume, poi l'evento pageshow)
passivo (tramite l'evento resume, poi l'evento pageshow)
nascosto (tramite l'evento resume)
eliminato (nessun evento attivato)

Risoluzione

Una pagina è nello stato terminata quando inizia a essere scaricata e cancellata dalla memoria dal browser. In questo stato non è possibile avviare nuove attività e quelle in corso potrebbero essere interrotte se vengono eseguite per troppo tempo.

Possibili stati precedenti:
hidden (tramite l'evento pagehide)

Possibili stati successivi:
NESSUNO

Ignorati

Una pagina è in stato discarded quando viene scaricata dal browser per risparmiare risorse. In questo stato non è possibile eseguire attività, callback di eventi o JavaScript di alcun tipo, poiché gli scarti si verificano in genere in caso di vincoli di risorse, in cui è impossibile avviare nuovi processi.

Nello stato eliminata, la scheda stessa (incluso il titolo della scheda e la favicon) è in genere visibile all'utente anche se la pagina non è più visibile.

Possibili stati precedenti:
hidden (no events fired)
frozen (no events fired)

Possibili stati successivi:
NESSUNO

Eventi

I browser inviano molti eventi, ma solo una piccola parte di questi segnala una possibile variazione dello stato del ciclo di vita della pagina. La tabella seguente illustra tutti gli eventi correlati al ciclo di vita ed elenca gli stati a cui possono passare e da cui possono uscire.

Nome Dettagli
focus

Un elemento DOM ha ricevuto lo stato attivo.

Nota: un evento focus non indica necessariamente una variazione di stato. Indica una modifica di stato solo se la pagina non aveva precedentemente il focus sull'input.

Possibili stati precedenti:
passive

Possibili stati attuali:
active

blur

Un elemento DOM ha perso il focus.

Nota: un evento blur non indica necessariamente una variazione di stato. Indica una modifica di stato solo se la pagina non ha più il focus sull'input (ovvero se la pagina non ha semplicemente trasferito il focus da un elemento all'altro).

Possibili stati precedenti:
active

Possibili stati attuali:
passive

visibilitychange

Il valore di visibilityState del documento è cambiato. Ciò può accadere quando un utente passa a una nuova pagina, cambia scheda, chiude una scheda, minimizza o chiude il browser o cambia app sui sistemi operativi mobile.

Possibili stati precedenti:
passive
hidden

Possibili stati attuali:
passive
hidden

freeze *

La pagina è stata appena bloccata. Qualsiasi attività bloccabile nelle code di attività della pagina non verrà avviata.

Possibili stati precedenti:
hidden

Possibili stati correnti:
frozen

resume *

Il browser ha ripreso una pagina congelata.

Possibili stati precedenti:
frozen

Possibili stati correnti:
attivo (se seguito dall'evento pageshow)
passivo (se seguito dall'evento pageshow)
nascosto

pageshow

È in corso l'esplorazione di una voce della cronologia delle sessioni.

Potrebbe trattarsi di un caricamento di una pagina nuova di zecca o di una pagina presa dalla cache back-forward. Se la pagina è stata acquisita dalla cache back/forward, la proprietà persisted dell'evento è true, altrimenti è false.

Possibili stati precedenti:
frozen (verrebbe attivato anche un evento resume)

Possibili stati attuali:
attivo
passivo
nascosto

pagehide

Viene attraversata una voce della cronologia delle sessioni.

Se l'utente passa a un'altra pagina e il browser è in grado di aggiungere la pagina corrente alla cache di navigazione вперед/назад per riutilizzarla in un secondo momento, la proprietà persisted dell'evento è true. Quando true, la pagina sta entrando nello stato congelata, altrimenti entra nello stato terminata.

Possibili stati precedenti:
hidden

Possibili stati correnti:
congelato (event.persisted è vero, segue l'evento freeze)
terminato (event.persisted è falso, segue l'evento unload)

beforeunload

La finestra, il documento e le relative risorse stanno per essere scaricati. Il documento è ancora visibile e l'evento è ancora annullabile in questo momento.

Importante: l'evento beforeunload deve essere utilizzato solo per avvisare l'utente delle modifiche non salvate. Una volta salvate queste modifiche, l'evento dovrebbe essere rimosso. Non deve mai essere aggiunto incondizionatamente alla pagina, in quanto in alcuni casi può compromettere il rendimento. Per maggiori dettagli, consulta la sezione relativa alle API legacy.

Possibili stati precedenti:
hidden

Possibili stati attuali:
terminated

unload

La pagina viene scaricata.

Avviso: l'utilizzo dell'evento unload non è mai consigliato perché non è affidabile e in alcuni casi può influire negativamente sul rendimento. Per ulteriori dettagli, consulta la sezione relativa alle API precedenti.

Possibili stati precedenti:
hidden

Possibili stati attuali:
terminated

* Indica un nuovo evento definito dall'API Page Lifecycle

Nuove funzionalità aggiunte in Chrome 68

Il grafico precedente mostra due stati avviati dal sistema anziché dall'utente: congelato e eliminato. Come accennato in precedenza, oggi i browser bloccano e ignorano occasionalmente le schede nascoste (a loro discrezione), ma gli sviluppatori non hanno modo di sapere quando accade.

In Chrome 68, gli sviluppatori ora possono osservare quando una scheda nascosta viene bloccata e sbloccata ascoltando gli eventi freeze e resume su document.

document.addEventListener('freeze', (event) => {
  // The page is now frozen.
});

document.addEventListener('resume', (event) => {
  // The page has been unfrozen.
});

A partire da Chrome 68, l'oggetto document ora include una proprietà wasDiscarded su Chrome per computer (il supporto di Android è in fase di monitoraggio in questo problema). Per determinare se una pagina è stata ignorata in una scheda nascosta, puoi controllare il valore di questa proprietà al momento del caricamento della pagina (nota: le pagine ignorate devono essere ricaricate per essere riutilizzate).

if (document.wasDiscarded) {
  // Page was previously discarded by the browser while in a hidden tab.
}

Per consigli su cosa è importante fare negli eventi freeze e resume, nonché su come gestire e prepararsi all'eliminazione delle pagine, consulta i consigli per gli sviluppatori per ogni stato.

Le sezioni successive offrono una panoramica di come queste nuove funzionalità si inseriscono negli stati e negli eventi della piattaforma web esistenti.

Come osservare gli stati del ciclo di vita della pagina nel codice

Negli stati active, passive e hidden, è possibile eseguire codice JavaScript che determina lo stato corrente del ciclo di vita della pagina dalle API della piattaforma web esistenti.

const getState = () => {
  if (document.visibilityState === 'hidden') {
    return 'hidden';
  }
  if (document.hasFocus()) {
    return 'active';
  }
  return 'passive';
};

Gli stati congelato e terminato, invece, possono essere rilevati solo nel rispettivo listener di eventi (freeze e pagehide) quando lo stato sta cambiando.

Come osservare le modifiche dello stato

Basandoti sulla funzione getState() definita in precedenza, puoi osservare tutte le modifiche dello stato del ciclo di vita della pagina con il seguente codice.

// Stores the initial state using the `getState()` function (defined above).
let state = getState();

// Accepts a next state and, if there's been a state change, logs the
// change to the console. It also updates the `state` value defined above.
const logStateChange = (nextState) => {
  const prevState = state;
  if (nextState !== prevState) {
    console.log(`State change: ${prevState} >>> ${nextState}`);
    state = nextState;
  }
};

// Options used for all event listeners.
const opts = {capture: true};

// These lifecycle events can all use the same listener to observe state
// changes (they call the `getState()` function to determine the next state).
['pageshow', 'focus', 'blur', 'visibilitychange', 'resume'].forEach((type) => {
  window.addEventListener(type, () => logStateChange(getState()), opts);
});

// The next two listeners, on the other hand, can determine the next
// state from the event itself.
window.addEventListener('freeze', () => {
  // In the freeze event, the next state is always frozen.
  logStateChange('frozen');
}, opts);

window.addEventListener('pagehide', (event) => {
  // If the event's persisted property is `true` the page is about
  // to enter the back/forward cache, which is also in the frozen state.
  // If the event's persisted property is not `true` the page is
  // about to be unloaded.
  logStateChange(event.persisted ? 'frozen' : 'terminated');
}, opts);

Questo codice esegue tre operazioni:

  • Imposta lo stato iniziale utilizzando la funzione getState().
  • Definisce una funzione che accetta uno stato successivo e, se si verifica una modifica, registra le modifiche dello stato nella console.
  • Aggiunge metodi di acquisizione per tutti gli eventi di ciclo di vita necessari, che a loro volta chiamano logStateChange() passando lo stato successivo.

Una cosa da notare sul codice è che tutti i listener di eventi vengono aggiunti a window e passano tutti {capture: true}. Ecco alcuni dei motivi:

  • Non tutti gli eventi del ciclo di vita della pagina hanno lo stesso target. pagehide e pageshow vengono attivati su window; visibilitychange, freeze e resume vengono attivati su document e focus e blur vengono attivati sui rispettivi elementi DOM.
  • La maggior parte di questi eventi non si propaga, il che significa che è impossibile aggiungere listener di eventi non di rilevamento a un elemento antenato comune e osservarli tutti.
  • La fase di acquisizione viene eseguita prima delle fasi target o bubble, quindi l'aggiunta di ascoltatori consente di assicurarsi che vengano eseguiti prima che altro codice possa annullarli.

Consigli per gli sviluppatori per ogni stato

In qualità di sviluppatori, è importante comprendere gli stati del ciclo di vita della pagina e sapere come osservarli nel codice perché il tipo di lavoro che dovresti (e non dovresti) svolgere dipende in gran parte dallo stato della pagina.

Ad esempio, non ha senso mostrare una notifica transitoria all'utente se la pagina è nello stato nascosto. Anche se questo esempio è abbastanza chiaro, esistono altri consigli meno evidenti che vale la pena elencare.

Stato Consigli per gli sviluppatori
Active

Lo stato active è il momento più critico per l'utente e quindi il momento più importante per la tua pagina per essere reattiva all'input dell'utente.

Qualsiasi attività non relativa all'interfaccia utente che potrebbe bloccare il thread principale deve essere riassegnata ai periodi di inattività o caricata su un web worker.

Passive

Nello stato Passivo l'utente non interagisce con la pagina, ma può comunque visualizzarla. Ciò significa che gli aggiornamenti e le animazioni dell'interfaccia utente dovrebbero essere ancora scorrevoli, ma i tempi di questi aggiornamenti sono meno critici.

Quando la pagina passa da attiva a passiva, è un buon momento per mantenere costante lo stato dell'applicazione non salvato.

Hidden

Quando la pagina passa da passiva a nascosta, è possibile che l'utente non interagisca di nuovo con la pagina finché non viene ricaricata.

La transizione a hidden è spesso anche l'ultima variazione di stato osservabile in modo affidabile dagli sviluppatori (questo è particolarmente vero su dispositivi mobili, in quanto gli utenti possono chiudere le schede o l'app del browser stessa e gli eventi beforeunload, pagehide e unload non vengono attivati in questi casi).

Ciò significa che devi considerare lo stato hidden come la probabile fine della sessione dell'utente. In altre parole, mantieni invariato lo stato dell'applicazione non salvato e invia eventuali dati di analisi non inviati.

Inoltre, dovresti interrompere gli aggiornamenti dell'interfaccia utente (poiché non verranno visualizzati dall'utente) e tutte le attività che un utente non vorrebbe eseguire in background.

Frozen

Nello stato congelato, le attività bloccabili nelle code di attività vengono sospese finché la pagina non viene scongelata, il che potrebbe non accadere mai (ad es. se la pagina viene eliminata).

Ciò significa che quando la pagina passa da nascosta a congelata, è essenziale interrompere eventuali timer o disconnettere eventuali connessioni che, se congelate, potrebbero influire su altre schede aperte nella stessa origine o sulla capacità del browser di inserire la pagina nella cache di spostamento avanti/indietro.

In particolare, è importante che tu:

Devi anche mantenere invariato qualsiasi stato di visualizzazione dinamico (ad es. la posizione di scorrimento in una visualizzazione elenco infinita) in sessionStorage (o IndexedDB tramite commit()) che vuoi ripristinare se la pagina viene eliminata e ricaricata in un secondo momento.

Se la pagina passa da congelata a nascosta, puoi riaprire le connessioni chiuse o riavviare eventuali polling che hai interrotto quando la pagina è stata inizialmente bloccata.

Terminated

In genere, non è necessario intraprendere alcuna azione quando una pagina passa allo stato Terminata.

Poiché le pagine che vengono scaricate a seguito di un'azione dell'utente passano sempre per lo stato hidden prima di entrare nello stato terminated, è nello stato hidden che deve essere eseguita la logica di chiusura della sessione (ad es. la persistenza dello stato dell'applicazione e i report per Analytics).

Inoltre, come indicato nei consigli per lo stato hidden, è molto importante che gli sviluppatori comprendano che la transizione allo stato terminated non può essere rilevata in modo affidabile in molti casi (in particolare sui dispositivi mobili), pertanto gli sviluppatori che si basano sugli eventi di interruzione (ad es. beforeunload, pagehide e unload) potrebbero perdere dati.

Discarded

Lo stato eliminata non è osservabile dagli sviluppatori al momento dell'eliminazione di una pagina. Questo perché le pagine vengono in genere eliminate in caso di limitazioni delle risorse e sbloccare una pagina solo per consentire l'esecuzione dello script in risposta a un evento di eliminazione non è semplicemente possibile nella maggior parte dei casi.

Di conseguenza, devi prepararti alla possibilità di un rifiuto nel passaggio da nascosto a congelato e poi puoi reagire al ripristino di una pagina ignorata al momento del caricamento della pagina controllando document.wasDiscarded.

Ancora una volta, poiché l'affidabilità e l'ordinamento degli eventi del ciclo di vita non sono implementati in modo coerente in tutti i browser, il modo più semplice per seguire i consigli riportati nella tabella è utilizzare PageLifecycle.js.

API di ciclo di vita legacy da evitare

Se possibile, evita i seguenti eventi.

L'evento unload

Molti sviluppatori trattano l'evento unload come un callback garantito e lo utilizzano come un indicatore di fine sessione per salvare lo stato e inviare i dati di analisi, ma questo approccio è estremamente inaffidabile, soprattutto sui dispositivi mobili. L'evento unload non viene attivato in molte situazioni di svuotamento tipiche, ad esempio la chiusura di una scheda dal selettore di schede sui dispositivi mobili o la chiusura dell'app del browser dal selettore di app.

Per questo motivo, è sempre meglio fare affidamento sull'evento visibilitychange per determinare quando termina una sessione e considerare lo stato nascosto come l'ultimo momento affidabile per salvare i dati dell'app e dell'utente.

Inoltre, la sola presenza di un gestore di eventi unload registrato (tramite onunload o addEventListener()) può impedire ai browser di inserire le pagine nella cache back-forward per caricamenti avanti e indietro più rapidi.

In tutti i browser moderni, è consigliabile utilizzare sempre l'evento pagehide per rilevare possibili svuotamenti della pagina (noto anche come stato terminato) anziché l'evento unload. Se devi supportare le versioni di Internet Explorer 10 e precedenti, devi rilevare l'evento pagehide e utilizzare unload solo se il browser non supporta pagehide:

const terminationEvent = 'onpagehide' in self ? 'pagehide' : 'unload';

window.addEventListener(terminationEvent, (event) => {
  // Note: if the browser is able to cache the page, `event.persisted`
  // is `true`, and the state is frozen rather than terminated.
});

L'evento beforeunload

L'evento beforeunload presenta un problema simile a quello dell'evento unload, in quanto, in passato, la presenza di un evento beforeunload poteva impedire alle pagine di essere idonee per la cache back/forward. I browser moderni non hanno questa limitazione. Tuttavia, alcuni browser, per precauzione, non attivano l'evento beforeunload quando tentano di inserire una pagina nella cache di spostamento вперед/назад, il che significa che l'evento non è affidabile come indicatore di fine sessione. Inoltre, alcuni browser (incluso Chrome) richiedono un'interazione dell'utente sulla pagina prima di consentire l'attivazione dell'evento beforeunload, compromettendo ulteriormente la sua affidabilità.

Una differenza tra beforeunload e unload è che esistono utilizzi legittimi di beforeunload. Ad esempio, quando vuoi avvisare l'utente che ha modifiche non salvate che perderà se continua a scaricare la pagina.

Poiché esistono motivi validi per utilizzare beforeunload, ti consigliamo di solo aggiungere ascoltatori beforeunload quando un utente ha modifiche non salvate, per poi rimuoverli immediatamente dopo il salvataggio.

In altre parole, non fare così (poiché aggiunge un ascoltatore beforeunload incondizionatamente):

addEventListener('beforeunload', (event) => {
  // A function that returns `true` if the page has unsaved changes.
  if (pageHasUnsavedChanges()) {
    event.preventDefault();

    // Legacy support for older browsers.
    return (event.returnValue = true);
  }
});

Esegui invece questa operazione (poiché aggiunge l'ascoltatore beforeunload solo quando è necessario e lo rimuove quando non è necessario):

const beforeUnloadListener = (event) => {
  event.preventDefault();
  
  // Legacy support for older browsers.
  return (event.returnValue = true);
};

// A function that invokes a callback when the page has unsaved changes.
onPageHasUnsavedChanges(() => {
  addEventListener('beforeunload', beforeUnloadListener);
});

// A function that invokes a callback when the page's unsaved changes are resolved.
onAllChangesSaved(() => {
  removeEventListener('beforeunload', beforeUnloadListener);
});

Domande frequenti

Perché non esiste uno stato "in caricamento"?

L'API Page Lifecycle definisce gli stati come discreti e reciprocamente esclusivi. Poiché una pagina può essere caricata nello stato attivo, passivo o nascosto e poiché può cambiare stato o addirittura essere interrotta prima del termine del caricamento, uno stato di caricamento distinto non ha senso in questo paradigma.

La mia pagina svolge un'attività importante quando è nascosta. Come faccio a impedire che venga bloccata o ignorata?

Esistono molti motivi legittimi per cui le pagine web non devono essere bloccate durante l'esecuzione in stato nascosto. L'esempio più ovvio è un'app che riproduce musica.

Esistono anche situazioni in cui sarebbe rischioso per Chrome eliminare una pagina, ad esempio se contiene un modulo con input utente non inviati o se ha un gestore beforeunload che avvisa quando la pagina viene scaricata.

Per il momento, Chrome sarà prudente quando eliminerà le pagine e lo farà solo quando avrà la certezza che non influirà sugli utenti. Ad esempio, le pagine per le quali è stato osservato che eseguono una delle seguenti operazioni nello stato nascosto non verranno eliminate, a meno che non si verifichino vincoli di risorse estremi:

  • Riproduzione audio
  • Utilizzo di WebRTC
  • Aggiornamento del titolo o della favicon della tabella
  • Visualizzazione di avvisi
  • Invio di notifiche push

Per le funzionalità dell'elenco corrente utilizzate per determinare se una scheda può essere messa in pausa o eliminata in sicurezza, consulta Euristiche per la messa in pausa ed l'eliminazione in Chrome.

Che cos'è la cache back-forward?

La cache avanti/indietro è un termine utilizzato per descrivere un'ottimizzazione della navigazione implementata da alcuni browser che consente di utilizzare più velocemente i pulsanti Indietro e Avanti.

Quando un utente esce da una pagina, questi browser bloccano una versione della pagina in modo che possa essere ripresa rapidamente nel caso in cui l'utente torni indietro utilizzando i pulsanti Indietro o Avanti. Ricorda che l'aggiunta di un gestore eventi unload impedisce questa ottimizzazione.

A tutti gli effetti, questo blocco è funzionalmente uguale a quello eseguito dai browser per risparmiare CPU/batteria; per questo motivo, è considerato parte dello stato di ciclo di vita congelato.

Se non riesco a eseguire API asincrone negli stati di blocco o terminazione, come faccio a salvare i dati in IndexedDB?

Negli stati di blocco e terminazione, le attività bloccabili nelle code di attesa delle attività di una pagina sono sospese, il che significa che le API asincrone e basate su callback come IndexedDB non possono essere utilizzate in modo affidabile.

In futuro, aggiungeremo un metodo commit() agli oggetti IDBTransaction, che offrirà agli sviluppatori un modo per eseguire transazioni di sola scrittura che non richiedono callback. In altre parole, se lo sviluppatore sta solo scrivendo dati in IndexedDB e non esegue una transazione complessa composta da letture e scritture, il metodo commit() potrà terminare prima che le code di attività vengano sospese (supponendo che il database IndexedDB sia già aperto).

Tuttavia, per il codice che deve funzionare oggi, gli sviluppatori hanno due opzioni:

  • Utilizza l'archiviazione di sessione: l'archiviazione di sessione è sincrona e viene mantenuta in tutte le pagine eliminate.
  • Utilizza IndexedDB dal tuo worker di servizio:un worker di servizio può memorizzare i dati in IndexedDB dopo la chiusura o l'eliminazione della pagina. Nell'ascoltatore di eventi freeze o pagehide puoi inviare dati al tuo service worker tramite postMessage(), e il service worker può gestire il salvataggio dei dati.

Testare l'app negli stati di sospensione e di eliminazione

Per testare il comportamento della tua app negli stati di sospensione e di eliminazione, puoi visitare chrome://discards per bloccare o eliminare effettivamente le tue schede aperte.

Interfaccia utente di Chrome Discards
Interfaccia utente di Chrome Discards

In questo modo puoi assicurarti che la pagina gestisca correttamente gli eventi freeze e resume nonché il flag document.wasDiscarded quando le pagine vengono ricaricate dopo un abbandono.

Riepilogo

Gli sviluppatori che vogliono rispettare le risorse di sistema dei dispositivi dei propri utenti devono creare le app tenendo presente gli stati del ciclo di vita della pagina. È fondamentale che le pagine web non consumino risorse di sistema eccessive in situazioni in cui l'utente non se lo aspetterebbe

Più sviluppatori iniziano a implementare le nuove API di ciclo di vita delle pagine, più sarà sicuro per i browser bloccare e ignorare le pagine non in uso. Ciò significa che i browser consumeranno meno memoria, CPU, batteria e risorse di rete, il che è un vantaggio per gli utenti.