API Page Lifecycle

Supporto dei browser

  • 68
  • 79
  • x
  • x

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

Contesto

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

Sul web, storicamente non esiste un ciclo di vita di questo tipo 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 sovraccaricate, causando un'esperienza negativa per l'utente finale.

Anche se la piattaforma web ospita 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 basso consumo (e in generale sia più consapevole delle risorse su tutte le piattaforme), i browser hanno bisogno di un modo per recuperare e riassegnare 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 farlo molto di più, per ridurre il consumo complessivo di risorse.

Il problema è che gli sviluppatori non hanno modo di prepararsi per questi tipi di interventi avviati dal sistema o persino di sapere che hanno luogo. Ciò significa che i browser devono essere conservativi o rischiare di compromettere le pagine web.

L'API Page Lifecycle prova a risolvere questo problema:

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

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

Il resto di questo post presenterà le nuove funzionalità del ciclo di vita delle pagine ed esplorerà la loro relazione con tutti gli stati e gli eventi esistenti delle piattaforme web. Fornirà inoltre consigli e best practice per i tipi di attività che gli sviluppatori dovrebbero (e non devono) svolgere in ogni stato.

Panoramica degli stati e degli eventi del ciclo di vita delle pagine

Tutti gli stati del ciclo di vita delle pagine sono discreti e si escludono a vicenda, ovvero una pagina può trovarsi in uno solo stato alla volta. Inoltre, la maggior parte delle modifiche allo stato del ciclo di vita di una pagina è generalmente osservabile tramite eventi DOM (consulta i suggerimenti per gli sviluppatori per ogni stato per le eccezioni).

Forse il modo più semplice per spiegare gli stati del ciclo di vita delle pagine, così come gli eventi che indicano le transizioni tra loro, è utilizzare un diagramma:

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

Stati

La tabella seguente illustra in dettaglio ogni stato. Elenca anche i possibili stati che possono verificarsi prima e dopo, nonché gli eventi che gli sviluppatori possono utilizzare per osservare i cambiamenti.

Stato Descrizione
Attivo

Una pagina è in stato attivo se è visibile e ha lo stato attivo per l'input.

Possibili stati precedenti:
passivo (tramite l'evento focus)
bloccato (tramite l'evento resume e poi l'evento pageshow)

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

Passivo

Una pagina è in stato passivo se è visibile e non è stata impostata per l'input.

Possibili stati precedenti:
attivo (tramite l'evento blur)
hidden (tramite l'evento visibilitychange)
bloccato (tramite l'evento resume, poi l'evento {21)/2pageshow

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

Nascosto

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

Possibili stati precedenti:
passivo (tramite l'evento visibilitychange)
congelato (tramite l'evento resume e poi l'evento pageshow)

Possibili stati successivi:
passivo (tramite l'evento visibilitychange)
bloccato (tramite l'evento freeze)
eliminato (nessun evento attivato)
terminato (nessun evento attivato)

Gelate

Quando lo stato è bloccato, il browser sospende l'esecuzione delle attività congelabili nelle code di attività della pagina finché la pagina non viene sbloccata. Ciò significa che elementi come i timer JavaScript e i callback di recupero non vengono eseguiti. Le attività già in esecuzione possono essere terminate (soprattutto il callback freeze), ma potrebbero avere limitazioni relative alle azioni che possono essere eseguite e alla loro durata.

I browser bloccano le pagine in modo da preservare l'utilizzo di CPU, batteria e dati. Lo fanno anche per consentire navigazioni back-forward più veloci, evitando di dover ricaricare l'intera pagina.

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

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

Terminata

Una pagina è nello stato terminata dopo che è iniziato l'unload e l'eliminazione dalla memoria del browser. Nessuna nuova attività può iniziare in questo stato e le attività in corso potrebbero essere interrotte se vengono eseguite troppo a lungo.

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

Possibili stati successivi:
NESSUNO

Ignorati

Una pagina è nello stato eliminato quando viene eseguito l'unload dal browser per risparmiare risorse. In questo stato non è possibile eseguire attività, callback di eventi o JavaScript di qualsiasi tipo, dato che gli scarti di solito avvengono in base a vincoli delle risorse, dove non è possibile avviare nuovi processi.

Nello stato esclusa, la scheda stessa (inclusi il titolo e la favicon) è solitamente visibile all'utente anche se la pagina è stata rimossa.

Possibili stati precedenti:
nascosto (nessun evento attivato)
bloccato (nessun evento attivato)

Possibili stati successivi:
NESSUNO

Eventi

I browser inviano molti eventi, ma solo una piccola parte segnala un possibile cambiamento nello stato del ciclo di vita della pagina. La tabella seguente illustra tutti gli eventi relativi al ciclo di vita ed elenca gli stati da e verso cui possono effettuare la transizione.

Nome Dettagli
focus

È stato attivato un elemento DOM.

Nota: un evento focus non segnala necessariamente un cambio di stato. Segnala un cambiamento di stato solo se in precedenza la pagina non era stata selezionata per l'input.

Possibili stati precedenti:
passivo

Possibili stati attuali:
attivo

blur

Un elemento DOM ha perso lo stato attivo.

Nota: un evento blur non segnala necessariamente un cambio di stato. Segnala un cambio di stato solo se la pagina non è più attiva per l'input (ovvero non è stata solo selezionata per lo stato attivo da un elemento all'altro).

Possibili stati precedenti:
attivo

Possibili stati attuali:
passivo

visibilitychange

Il valore visibilityState del documento è stato modificato. Questo può accadere quando un utente apre una nuova pagina, cambia scheda, chiude una scheda, riduce a icona o chiude il browser oppure cambia app sui sistemi operativi mobile.

Possibili stati precedenti:
passivo
nascosto

Possibili stati attuali:
passivo
nascosto

freeze *

La pagina è appena stata bloccata. Le attività congelabili nelle code di attività della pagina non verranno avviate.

Possibili stati precedenti:
nascosti

Possibili stati attuali:
bloccato

resume *

Il browser ha ripristinato una pagina bloccata.

Possibili stati precedenti:
bloccato

Possibili stati attuali:
attivo (se seguito dall'evento pageshow)
passivo (se seguito dall'evento pageshow)
hidden

pageshow

È in corso il trasferimento di una voce della cronologia della sessione.

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

Possibili stati precedenti:
bloccato (anche un evento resume sarebbe stato attivato)

Possibili stati attuali:
attivo
passivo
nascosto

pagehide

È in corso il trasferimento di una voce della cronologia della sessione.

Se l'utente passa a un'altra pagina e il browser è in grado di aggiungere la pagina corrente alla cache back/forward per riutilizzarla in un secondo momento, la proprietà persisted dell'evento è true. Quando true, la pagina entra nello stato bloccato, altrimenti entra nello stato terminata.

Possibili stati precedenti:
nascosti

Possibili stati attuali:
bloccato (event.persisted è true, l'evento freeze segue)
terminato (event.persisted è false, segue l'evento unload)

beforeunload

Stai per eseguire l'unload della finestra, del documento e delle relative risorse. A questo punto il documento è ancora visibile e l'evento può essere ancora annullato.

Importante: l'evento beforeunload deve essere utilizzato solo per avvisare l'utente di modifiche non salvate. Una volta salvate queste modifiche, l'evento dovrebbe essere rimosso. Non dovrebbe mai essere aggiunto incondizionatamente alla pagina, poiché in alcuni casi potrebbe compromettere le prestazioni. Consulta la sezione API legacy per i dettagli.

Possibili stati precedenti:
nascosti

Possibili stati attuali:
terminato

unload

È in corso l'unload della pagina.

Avviso: l'utilizzo dell'evento unload non è mai consigliato perché non è affidabile e in alcuni casi può compromettere le prestazioni. Consulta la sezione delle API legacy per ulteriori dettagli.

Possibili stati precedenti:
nascosti

Possibili stati attuali:
terminato

* 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: bloccato e eliminato. Come accennato in precedenza, già oggi i browser si bloccano ed eliminano le schede nascoste (a loro discrezione), ma gli sviluppatori non hanno modo di sapere quando questo accade.

In Chrome 68, ora gli sviluppatori 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 (per questo problema è in corso il monitoraggio del supporto di Android). Per determinare se una pagina è stata eliminata in una scheda nascosta, puoi controllarne il valore al momento del caricamento della pagina (nota: le pagine eliminate devono essere ricaricate per poter essere utilizzate di nuovo).

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

Per consigli sulle cose importanti da fare negli eventi freeze e resume, nonché su come gestire e preparare le pagine che verranno eliminate, consulta i consigli per gli sviluppatori per ogni stato.

Le prossime sezioni offrono una panoramica di come queste nuove funzionalità si adattano agli stati e agli eventi delle piattaforme web esistenti.

Come osservare gli stati del ciclo di vita delle pagine nel codice

Nello stato attivo, passivo e nascosto, è possibile eseguire il codice JavaScript che determina l'attuale stato del ciclo di vita della pagina dalle API delle piattaforme web esistenti.

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

Gli stati bloccato e terminato, invece, possono essere rilevati solo nel rispettivo listener di eventi (freeze e pagehide) mentre lo stato cambia.

Come osservare i cambiamenti di stato

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

// 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 ha tre funzioni:

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

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

  • Non tutti gli eventi del ciclo di vita delle pagine hanno lo stesso target. pagehide e pageshow vengono attivati su window; visibilitychange, freeze e resume vengono attivati su document, mentre focus e blur vengono attivati sui rispettivi elementi DOM.
  • La maggior parte di questi eventi non mostra le bolle, il che significa che è impossibile aggiungere listener di eventi non catturanti a un elemento predecessore comune e osservarli tutti.
  • La fase di acquisizione viene eseguita prima delle fasi di destinazione o bubble, quindi l'aggiunta di ascoltatori in questa fase garantisce l'esecuzione prima che un altro codice possa annullarle.

Consigli per gli sviluppatori per ogni stato

Per gli sviluppatori è importante comprendere gli stati del ciclo di vita delle pagine e saper 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 temporanea all'utente se la pagina è in stato nascosto. Sebbene questo esempio sia piuttosto ovvio, ci sono altri consigli non così ovvi che vale la pena enunciare.

Stato Consigli per gli sviluppatori
Active

Lo stato attivo è il momento più critico per l'utente, quindi il momento più importante affinché la pagina sia adattabile all'input dell'utente.

Qualsiasi operazione non UI che potrebbe bloccare il thread principale deve ridurre la priorità a periodi di inattività o ricaricarla a un web worker.

Passive

Nello stato passivo, l'utente non interagisce con la pagina, ma può comunque vederla. Ciò significa che gli aggiornamenti e le animazioni dell'interfaccia utente devono comunque essere fluidi, ma la tempistica di questi aggiornamenti è meno critica.

Quando la pagina passa da attiva a passiva, è un buon momento per mantenere 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'ultimo cambiamento di stato osservabile in modo affidabile dagli sviluppatori (questo vale in particolare sui dispositivi mobili, in quanto gli utenti possono chiudere le schede o l'app browser stessa e gli eventi beforeunload, pagehide e unload non vengono attivati in questi casi).

Ciò significa che dovresti considerare lo stato nascosto come la probabile fine della sessione dell'utente. In altre parole, mantieni eventuali stati dell'applicazione non salvati e invia eventuali dati di analisi non inviati.

Devi anche interrompere gli aggiornamenti dell'interfaccia utente (dal momento che non saranno visibili all'utente) e interrompere tutte le attività che un utente non vorrebbe eseguire in background.

Frozen

Nello stato bloccato, le attività bloccabili nelle code di attività vengono sospese fino a quando la pagina non viene sbloccata, il che potrebbe non verificarsi mai (ad esempio se la pagina viene eliminata).

Ciò significa che quando la pagina passa da nascosta a bloccata, è essenziale interrompere eventuali timer o eliminare le connessioni che, se bloccate, potrebbero influire su altre schede aperte nella stessa origine o sulla capacità del browser di inserire la pagina nella cache back-forward.

In particolare, è importante:

Devi inoltre mantenere qualsiasi stato di visualizzazione dinamica (ad esempio la posizione di scorrimento in una visualizzazione a elenco infinita) su sessionStorage (o IndexedDB tramite commit()) che vorresti ripristinare nel caso in cui la pagina fosse stata ignorata e ricaricata in un secondo momento.

Se la pagina passa da bloccata a nascosta, puoi riaprire le connessioni chiuse o riavviare qualsiasi polling interrotto quando la pagina era inizialmente bloccata.

Terminated

In genere non è necessario alcun intervento da parte tua quando una pagina passa allo stato terminata.

Poiché le pagine sottoposte a unload in seguito a un'azione dell'utente passano sempre allo stato nascosto prima di entrare nello stato terminata, lo stato nascosto è quello in cui deve essere eseguita la logica di fine sessione (ad es. stato dell'applicazione permanente e reporting ad analisi).

Inoltre, come accennato nei consigli per lo stato nascosto, è molto importante che gli sviluppatori comprendano che la transizione allo stato terminato non può essere rilevata in modo affidabile in molti casi (in particolare sui dispositivi mobili), quindi è probabile che gli sviluppatori che dipendono da eventi di terminazione (ad es. beforeunload, pagehide e unload) perdano probabilmente i dati.

Discarded

Lo stato eliminato non è osservabile dagli sviluppatori nel momento in cui viene eliminata una pagina. Questo perché le pagine vengono generalmente ignorate in base ai vincoli delle risorse e nella maggior parte dei casi non è possibile sbloccare una pagina solo per consentire l'esecuzione dello script in risposta a un evento di eliminazione.

Di conseguenza, devi prepararti alla possibilità di un'eliminazione nella modifica da hidden a bloccata, quindi puoi reagire al ripristino di una pagina eliminata al momento del caricamento della pagina selezionando document.wasDiscarded.

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

API con ciclo di vita legacy da evitare

Se possibile, evita i seguenti eventi.

L'evento unload

Molti sviluppatori considerano l'evento unload come un callback garantito e lo utilizzano come indicatore di fine sessione per salvare lo stato e inviare dati di analisi, ma farlo è estremamente inaffidabile, soprattutto sui dispositivi mobili. L'evento unload non viene attivato in molte situazioni di unload 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 attendibile per salvare i dati dell'app e dell'utente.

Inoltre, la semplice 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 più rapidi in avanti e indietro.

In tutti i browser moderni, consigliamo di utilizzare sempre l'evento pagehide per rilevare i possibili unload delle pagine, ovvero lo stato terminato, anziché l'evento unload. Se devi supportare Internet Explorer 10 e versioni precedenti, dovresti 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 ha un problema simile all'evento unload, in quanto storicamente la presenza di un evento beforeunload potrebbe impedire alle pagine di essere idonee per la cache back-forward. I browser moderni non hanno questa restrizione. Anche se alcuni browser, per precauzione, non attivano l'evento beforeunload quando si cerca di inserire una pagina nella cache back-forward, il che significa che l'evento non è affidabile come indicatore di fine sessione. Inoltre, alcuni browser (tra cui Chrome) richiedono un'interazione dell'utente sulla pagina prima di consentire l'attivazione dell'evento beforeunload, il che influisce ulteriormente sulla sua affidabilità.

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

Poiché esistono validi motivi per utilizzare beforeunload, si consiglia di aggiungere listener beforeunload solo quando un utente dispone di modifiche non salvate e poi rimuoverli immediatamente dopo il salvataggio.

In altre parole, non eseguire questa operazione (dato che aggiunge un listener beforeunload senza condizioni):

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 questa operazione (dal momento che aggiunge il listener 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 è presente lo stato di "caricamento"?

L'API Page Lifecycle definisce gli stati discreti e si escludono a vicenda. Poiché una pagina può essere caricata nello stato attivo, passivo o nascosto e può cambiare stato (o persino essere terminata) prima che termini il caricamento, uno stato di caricamento separato non ha senso all'interno di questo paradigma.

La mia pagina funziona importante quando è nascosta. Come faccio a evitare che venga bloccata o eliminata?

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

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

Per il momento, Chrome è conservativo quando elimini le pagine e lo fa solo quando è sicuro che non influisca sugli utenti. Ad esempio, le pagine in cui è stato osservato che, in stato nascosto, eseguono una delle seguenti operazioni:

  • Riproduzione dell'audio in corso...
  • Utilizzo di WebRTC
  • Aggiornamento del titolo o della favicon della tabella
  • Visualizzazione degli avvisi
  • Invio di notifiche push

Per le funzionalità dell'elenco attuali utilizzate per determinare se una scheda può essere bloccata in sicurezza o eliminata, consulta la pagina Euristica per il blocco ed eliminazione di Chrome.

Che cos'è la cache back-forward?

Cache back/forward è un termine utilizzato per descrivere un'ottimizzazione della navigazione implementata da alcuni browser che velocizza l'utilizzo dei pulsanti Indietro e Avanti.

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

A tutti gli effetti, questo blocco funziona come previsto dai browser per risparmiare CPU/batteria; per questo motivo è considerato parte dello stato del ciclo di vita bloccato.

Se non riesco a eseguire API asincrone negli stati bloccati o terminati, come posso salvare i dati in IndexedDB?

Nello stato bloccato e terminato, le attività bloccabili nelle code di attività di una pagina vengono 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 per offrire 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 sta eseguendo 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 stesso, gli sviluppatori hanno due opzioni:

  • Utilizza l'archiviazione della sessione: l'archiviazione della sessione è sincrona e persistente in tutte le eliminazioni di pagine.
  • Utilizza IndexedDB dal tuo service worker: un service worker può archiviare dati in IndexedDB dopo che la pagina è stata terminata o eliminata. Nel listener di eventi freeze o pagehide puoi inviare dati al service worker tramite postMessage() e il service worker può gestire il salvataggio dei dati.

Test dell'app negli stati bloccati ed eliminati

Per verificare il comportamento dell'app negli stati bloccati ed eliminati, puoi visitare la pagina chrome://discards per bloccare o eliminare le schede aperte.

UI di eliminazione di Chrome
UI di Chrome Ignora

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 eliminazione.

Riepilogo

Gli sviluppatori che vogliono rispettare le risorse di sistema dei dispositivi degli utenti devono creare le app tenendo presente gli stati del ciclo di vita delle pagine. È fondamentale che le pagine web non consumino risorse di sistema eccessive in situazioni che l'utente non si aspetta

Più sviluppatori iniziano a implementare le nuove API del ciclo di vita delle pagine, più sicuro sarà il blocco e l'eliminazione delle pagine che non vengono utilizzate dai browser. Ciò significa che i browser consumano meno memoria, CPU, batteria e risorse di rete, il che è positivo per gli utenti.