Una buona parte delle navigazioni su un sito avviene con i tasti Indietro e Avanti: si apre una scheda prodotto, si torna all'elenco, se ne apre un'altra. Se ogni ritorno costringe il browser a scaricare, analizzare ed eseguire di nuovo la pagina, l'utente paga ogni volta il prezzo pieno del caricamento. La back/forward cache, abbreviata in bfcache, elimina questo costo: conserva in memoria l'intera pagina, compreso lo stato JavaScript, e la ripristina in pochi millisecondi.
È una delle ottimizzazioni con il miglior rapporto tra sforzo e risultato, perché non richiede di scrivere nuovo codice: basta non impedirla.
Come funziona
Quando l'utente lascia una pagina, il browser invece di distruggerla la "congela": sospende i timer, mette in pausa l'esecuzione degli script e tiene in memoria il DOM e l'heap JavaScript. Se l'utente torna indietro, la pagina viene "scongelata" esattamente com'era, con lo scroll nella stessa posizione, i campi dei moduli compilati e le variabili intatte.
È una cosa diversa dalla cache HTTP. La cache HTTP evita di riscaricare i file, ma la pagina deve comunque essere ricostruita: HTML analizzato, CSS applicato, script eseguiti. La bfcache salta tutto questo, ed è per questo che il ritorno appare istantaneo.
Cosa impedisce il ripristino
Il browser rinuncia a mettere una pagina in bfcache quando teme che congelarla possa rompere qualcosa. Le cause più frequenti sono:
- gestori dell'evento
unload: sono il motivo classico. Il browser non può garantire cheunloadvenga eseguito se la pagina è conservata, e in diversi casi preferisce escluderla; - intestazione
Cache-Control: no-storesul documento HTML: indica che la pagina non deve essere conservata e, a seconda del browser, può escluderla dalla bfcache; - connessioni aperte al momento dell'uscita, come WebSocket, WebRTC o richieste ancora in corso, che il browser non sa come sospendere;
- finestre aperte con
window.openerche mantengono un riferimento reciproco tra pagine; - API particolari in uso, come alcune funzioni di accesso a dispositivi.
Molti di questi blocchi arrivano da script di terze parti: un widget di chat che apre un WebSocket o una libreria di analytics che registra un gestore unload possono escludere tutte le pagine del sito.
Sostituire unload con pagehide
L'evento unload era usato per inviare dati all'uscita, per esempio una statistica di sessione. Ma è inaffidabile anche senza considerare la bfcache: sui dispositivi mobili spesso non viene eseguito affatto, perché il sistema chiude la scheda senza preavviso.
Le alternative corrette sono:
pagehide, che scatta quando la pagina viene lasciata, sia che finisca in bfcache sia che venga distrutta;visibilitychangecon statohidden, che scatta anche quando l'utente passa a un'altra app ed è il momento più affidabile per inviare dati.
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
navigator.sendBeacon('/statistiche', JSON.stringify(datiSessione));
}
});
sendBeacon accoda la richiesta in modo che venga completata anche se la pagina viene chiusa subito dopo.
Gestire il ritorno dalla bfcache
Una pagina ripristinata non riceve un nuovo evento load, e questo può sorprendere. Se il codice aggiorna qualcosa solo al caricamento, per esempio il numero di articoli nel carrello, dopo un ritorno potrebbe mostrare dati vecchi. Per intercettare il ripristino si usa pageshow con la proprietà persisted:
window.addEventListener('pageshow', (evento) => {
if (evento.persisted) {
aggiornaCarrello();
registraVisualizzazione();
}
});
Allo stesso modo, se apri connessioni durature, chiudile in pagehide e riaprile in pageshow: in questo modo non bloccano la bfcache e la pagina resta funzionante dopo il ritorno.
Dati sensibili
Per le pagine con informazioni personali, come un'area riservata dopo il logout, il timore è che il tasto Indietro mostri dati che non dovrebbero più essere visibili. La soluzione più pulita non è vietare la bfcache, ma controllare lo stato di autenticazione nel gestore pageshow e, se la sessione è terminata, ricaricare o reindirizzare. Così si protegge l'utente senza rinunciare alla velocità sul resto del sito.
Verificare con gli strumenti
Chrome DevTools offre un test dedicato nel pannello Application, alla voce Back/forward cache. Premendo il pulsante di test, il browser naviga altrove e torna indietro, poi riporta se la pagina è stata ripristinata e, in caso contrario, l'elenco dei motivi. I motivi sono divisi in categorie: quelli risolvibili dallo sviluppatore, quelli in attesa di supporto da parte del browser e quelli non risolvibili.
Anche Lighthouse include un controllo che segnala le pagine escluse dalla bfcache. Per i dati reali, Chrome espone sulle voci di navigazione la proprietà notRestoredReasons, che permette di raccogliere dagli utenti veri i motivi del mancato ripristino.
| Sintomo | Causa probabile | Intervento |
|---|---|---|
| Ritorno lento su tutte le pagine | Script con unload |
Passare a pagehide o visibilitychange |
| Escluse solo le pagine con la chat | WebSocket aperto | Chiuderlo in pagehide, riaprirlo in pageshow |
| Escluse le pagine dinamiche | no-store sull'HTML |
Valutare no-cache o private |
| Dati vecchi dopo il ritorno | Logica legata a load |
Aggiornare in pageshow con persisted |
In sintesi
- La bfcache conserva in memoria la pagina intera e la ripristina all'istante con Indietro e Avanti.
- Il nemico principale è l'evento
unload: sostituiscilo conpagehideovisibilitychange. - Usa
pageshowconpersistedper aggiornare i dati dopo un ripristino. - Chiudi connessioni aperte all'uscita e riaprile al ritorno.
- Verifica con il test di DevTools e raccogli i motivi dagli utenti reali.