Esistono molte opzioni diverse per archiviare i dati nel browser. Qual è il più adatto alle tue esigenze?
Le connessioni a internet possono essere instabili o inesistenti quando sei in viaggio, motivo per cui il supporto offline e le prestazioni affidabili sono funzionalità comuni nelle app web progressive. Anche in ambienti wireless perfetti, un uso oculato della memorizzazione nella cache e di altre tecniche di archiviazione può migliorare notevolmente l'esperienza utente. Esistono diversi modi per memorizzare nella cache le risorse statiche dell'applicazione (HTML, JavaScript, CSS, immagini e così via) e i dati (dati utente, articoli e così via). Ma qual è la soluzione migliore? Quanto puoi archiviare? Come si fa a evitare che venga espulso?
Quale dovrei utilizzare?
Ecco un suggerimento generale per l'archiviazione delle risorse:
- Per le risorse di rete necessarie per caricare l'app, utilizza l'API Cache Storage (parte dei service worker).
- Per i contenuti basati su file, utilizza l'Origin Private File System (OPFS).
- Per altri dati, utilizza IndexedDB (con un wrapper di promise).
IndexedDB, OPFS e l'API Cache Storage sono supportati in tutti i browser moderni.
Sono asincrone e non bloccano il thread principale (ma esiste anche una variante sincrona
dell'OPFS disponibile esclusivamente nei web worker). Sono accessibili dall'oggetto window, dai web worker e dai service worker, il che consente di utilizzarli ovunque nel codice.
E per quanto riguarda gli altri meccanismi di archiviazione?
Nel browser sono disponibili diversi altri meccanismi di archiviazione, ma hanno un utilizzo limitato e possono causare problemi di prestazioni significativi.
SessionStorage è specifico per la scheda e ha un ambito limitato alla durata della scheda. Può essere utile per archiviare piccole quantità di informazioni specifiche della sessione, ad esempio una chiave IndexedDB. Deve essere utilizzato con cautela perché è sincrono e blocca il thread principale. È limitato a circa 5 MB e può contenere solo stringhe. Poiché è specifica per la scheda, non è accessibile da web worker o service worker.
L'utilizzo di LocalStorage deve essere evitato perché è sincrono e blocca il thread principale. È limitato a circa 5 MB e può contenere solo stringhe. LocalStorage non è accessibile da web worker o service worker.
I cookie hanno i loro usi, ma non devono essere utilizzati per l'archiviazione. I cookie vengono inviati con ogni richiesta HTTP, quindi l'archiviazione di una quantità di dati superiore a una piccola quantità aumenterà in modo significativo le dimensioni di ogni richiesta web. Sono sincrone e non sono accessibili dai web worker. Come LocalStorage e SessionStorage, i cookie sono limitati solo alle stringhe.
L'API File System Access è stata progettata per consentire agli utenti di leggere e modificare i file nel file system locale. L'utente deve concedere l'autorizzazione prima che una pagina possa leggere o scrivere su un file locale e le autorizzazioni non vengono mantenute tra le sessioni, a meno che un handle di file non venga memorizzato nella cache in IndexedDB. L'API File System Access è più adatta per casi d'uso come gli editor, in cui devi aprire un file, modificarlo ed eventualmente salvare le modifiche nel file.
L'API File System e l'API FileWriter forniscono metodi per leggere e scrivere file in un file system in sandbox. Sebbene sia asincrono, non è consigliato perché è disponibile solo nei browser basati su Chromium.
Quanto spazio di archiviazione ho a disposizione?
In breve, molto, almeno un paio di centinaia di megabyte e potenzialmente centinaia di gigabyte o più. Le implementazioni dei browser variano, ma la quantità di spazio di archiviazione disponibile si basa in genere sulla quantità di spazio di archiviazione disponibile sul dispositivo.
- Chrome consente al browser di utilizzare fino all'80% dello spazio su disco totale. Un'origine può utilizzare fino al 60% dello spazio su disco totale. Puoi utilizzare l'API StorageManager per determinare la quota massima disponibile. Altri browser basati su Chromium potrebbero essere diversi.
- In modalità Incognito, Chrome riduce la quantità di spazio di archiviazione che un'origine può utilizzare a circa il 5% dello spazio su disco totale.
- Se l'utente ha attivato l'opzione "Cancella cookie e dati dei siti alla chiusura di tutte le finestre" in Chrome, la quota di spazio di archiviazione viene ridotta notevolmente fino a un massimo di circa 300 MB.
- Firefox consente al browser di utilizzare fino al 50% dello spazio su disco libero. Un gruppo eTLD+1 (ad es.
example.com,www.example.comefoo.bar.example.com) può utilizzare fino a 2 GB. Puoi utilizzare l'API StorageManager per determinare quanto spazio è ancora disponibile. - Safari (sia per computer che per dispositivi mobili) sembra consentire circa 1 GB. Quando viene raggiunto il limite, Safari chiede all'utente di aumentarlo con incrementi di 200 MB. Non sono riuscito a trovare alcuna documentazione ufficiale in merito.
- Se una PWA viene aggiunta alla schermata Home su Safari per dispositivi mobili, viene creato un nuovo contenitore di archiviazione e non viene condiviso nulla tra la PWA e Safari per dispositivi mobili. Una volta raggiunta la quota per una PWA installata, non sembra esserci un modo per richiedere spazio di archiviazione aggiuntivo.
In passato, se un sito superava una determinata soglia di dati archiviati, il browser chiedeva all'utente di concedere l'autorizzazione per utilizzare più dati. Ad esempio, se l'origine utilizzava più di 50 MB, il browser chiedeva all'utente di consentire l'archiviazione di un massimo di 100 MB, quindi chiedeva di nuovo con incrementi di 50 MB.
Oggi, la maggior parte dei browser moderni non chiede conferma all'utente e consente a un sito di utilizzare fino alla quota assegnata. L'eccezione sembra essere Safari, che mostra un messaggio quando viene superata la quota di spazio di archiviazione, richiedendo l'autorizzazione per aumentare la quota assegnata. Se un'origine tenta di utilizzare più della quota assegnata, i successivi tentativi di scrittura dei dati non andranno a buon fine.
Come faccio a controllare quanto spazio di archiviazione è disponibile?
In molti browser, puoi utilizzare l'API StorageManager per determinare la quantità di spazio di archiviazione disponibile per l'origine e la quantità di spazio di archiviazione in uso. Riporta il numero totale di byte utilizzati da IndexedDB e dall'API Cache e consente di calcolare lo spazio di archiviazione rimanente approssimativo disponibile.
if (navigator.storage && navigator.storage.estimate) {
const quota = await navigator.storage.estimate();
// quota.usage -> Number of bytes used.
// quota.quota -> Maximum number of bytes available.
const percentageUsed = (quota.usage / quota.quota) * 100;
console.log(`You've used ${percentageUsed}% of the available storage.`);
const remaining = quota.quota - quota.usage;
console.log(`You can write up to ${remaining} more bytes.`);
}
Devi rilevare gli errori di superamento della quota (vedi sotto). In alcuni casi, è possibile che la quota disponibile superi la quantità effettiva di spazio di archiviazione disponibile.
Ispeziona
Durante lo sviluppo, puoi utilizzare DevTools del browser per ispezionare i diversi tipi di spazio di archiviazione e cancellare tutti i dati archiviati.
In Chrome 88 è stata aggiunta una nuova funzionalità che ti consente di eseguire l'override della quota di spazio di archiviazione del sito nel riquadro Spazio di archiviazione. Questa funzionalità ti consente di simulare diversi dispositivi e testare il comportamento delle tue app in scenari di disponibilità ridotta del disco. Vai ad Applicazione, poi ad Archiviazione, attiva la casella di controllo Simula quota di spazio di archiviazione personalizzata e inserisci un numero valido per simulare la quota di spazio di archiviazione.
Come gestire il superamento della quota?
Cosa devi fare se superi la quota? Soprattutto, devi sempre rilevare e gestire gli errori di scrittura, che si tratti di un QuotaExceededError o di un altro errore. Quindi, a seconda del design della tua app, decidi come gestirlo.
Ad esempio, elimina i contenuti a cui non viene eseguito l'accesso da molto tempo, rimuovi i dati in base alle dimensioni o fornisci agli utenti un modo per scegliere cosa eliminare.
Sia IndexedDB che l'API Cache generano un errore DOMError denominato QuotaExceededError quando hai superato la quota disponibile.
IndexedDB
Se l'origine ha superato la quota, i tentativi di scrittura su IndexedDB non andranno a buon fine. Verrà chiamato il gestore onabort() della transazione, passando un evento.
L'evento includerà un DOMException nella proprietà di errore. Il controllo dell'errore name restituirà QuotaExceededError.
const transaction = idb.transaction(['entries'], 'readwrite');
transaction.onabort = function(event) {
const error = event.target.error; // DOMException
if (error.name == 'QuotaExceededError') {
// Fallback code goes here
}
};
API Cache
Se l'origine ha superato la quota, i tentativi di scrittura nell'API Cache verranno rifiutati con un errore QuotaExceededError DOMException.
try {
const cache = await caches.open('my-cache');
await cache.add(new Request('/sample1.jpg'));
} catch (err) {
if (error.name === 'QuotaExceededError') {
// Fallback code goes here
}
}
Come funziona l'eliminazione?
Lo spazio di archiviazione web è suddiviso in due categorie: "Best effort" e "Persistente". Best effort significa che lo spazio di archiviazione può essere cancellato dal browser senza interrompere l'utente, ma è meno durevole per i dati a lungo termine o critici. Lo spazio di archiviazione permanente non viene cancellato automaticamente quando lo spazio di archiviazione è in esaurimento. L'utente deve cancellare manualmente questo spazio di archiviazione (tramite le impostazioni del browser).
Per impostazione predefinita, i dati di un sito (tra cui IndexedDB, API Cache e così via) rientrano nella categoria best effort, il che significa che, a meno che un sito non abbia richiesto l'archiviazione permanente, il browser potrebbe rimuovere i dati del sito a sua discrezione, ad esempio quando lo spazio sul dispositivo è in esaurimento.
La policy di espulsione per il livello best effort è:
- I browser basati su Chromium inizieranno a rimuovere i dati quando lo spazio sul browser si esaurisce, cancellando tutti i dati dei siti prima dall'origine utilizzata meno di recente, poi dalla successiva, finché il browser non rientra nel limite.
- Firefox inizierà a rimuovere i dati quando lo spazio su disco disponibile sarà esaurito, cancellando tutti i dati del sito dall'origine utilizzata meno di recente, poi dalla successiva e così via, finché il browser non rientrerà nel limite.
- In precedenza, Safari non eliminava i dati, ma di recente ha implementato un nuovo limite di sette giorni per tutto lo spazio di archiviazione scrivibile (vedi di seguito).
A partire da iOS e iPadOS 13.4 e Safari 13.1 su macOS, esiste un limite di sette giorni per tutto lo spazio di archiviazione scrivibile tramite script, inclusi IndexedDB, la registrazione dei service worker e l'API Cache. Ciò significa che Safari rimuoverà tutti i contenuti dalla cache dopo sette giorni di utilizzo di Safari se l'utente non interagisce con il sito. Questa policy di rimozione non si applica alle PWA installate che sono state aggiunte alla schermata Home. Per informazioni dettagliate, consulta l'articolo Full Third-Party Cookie Blocking and More (Blocco completo dei cookie di terze parti e altro) sul blog di WebKit.
Bucket di archiviazione
L'idea di base dell'API Storage Buckets è consentire ai siti di creare più bucket di archiviazione, in modo che il browser possa scegliere di eliminare ogni bucket indipendentemente dagli altri. In questo modo, gli sviluppatori possono specificare la priorità di rimozione per assicurarsi che i dati più importanti non vengano eliminati.
Bonus: Perché utilizzare un wrapper per IndexedDB
IndexedDB è un'API di basso livello che richiede una configurazione significativa prima dell'uso, il che può essere particolarmente difficile per l'archiviazione di dati a bassa complessità. A differenza della maggior parte delle moderne API basate su promise, è basata sugli eventi. I wrapper di Promise come idb per IndexedDB nascondono alcune delle potenti funzionalità, ma soprattutto nascondono i meccanismi complessi (ad es. transazioni, controllo delle versioni dello schema) che accompagnano la libreria IndexedDB.
Bonus: SQLite Wasm
Dopo che Web SQL è stato ritirato e rimosso da Chrome, Google ha collaborato con i gestori del popolare database SQLite per offrire un sostituto di Web SQL basato su SQLite. Per informazioni dettagliate su come utilizzarlo, leggi SQLite Wasm nel browser supportato da Origin Private File System.
Conclusione
Sono finiti i tempi dello spazio di archiviazione limitato e della richiesta all'utente di archiviare sempre più dati. I siti possono archiviare in modo efficace tutte le risorse e i dati di cui hanno bisogno per funzionare. Utilizzando l'API StorageManager puoi determinare la quantità di spazio disponibile e quella che hai utilizzato. Inoltre, con l'archiviazione permanente, puoi proteggere i dati dall'eliminazione, a meno che non sia l'utente a rimuoverli.
Risorse aggiuntive
Grazie
Un ringraziamento speciale a Jarryd Goodman, Phil Walton, Eiji Kitamura, Daniel Murphy, Darwin Huang, Josh Bell, Marijn Kruisselbrink e Victor Costan per aver esaminato questa guida. Grazie a Eiji Kitamura, Addy Osmani e Marc Cohen, che hanno scritto gli articoli originali su cui si basa questo articolo. Eiji ha scritto un utile strumento chiamato Browser Storage Abuser che è stato utile per convalidare il comportamento attuale. Ti consente di archiviare quanti più dati possibile e di visualizzare i limiti di spazio di archiviazione sul tuo browser. Grazie a François Beaufort che ha fatto ricerche su Safari per capire i suoi limiti di archiviazione e a Thomas Steiner per aver aggiunto informazioni sul file system privato di origine, sui bucket di archiviazione, su SQLite Wasm e su un aggiornamento generale dei contenuti nel 2024.