Spazio di archiviazione per il Web

Esistono molte opzioni diverse per l'archiviazione dei dati nel browser. Qual è il più adatto alle tue esigenze?

Le connessioni a internet possono essere instabili o non esistenti quando sei in viaggio, motivo per cui il supporto offline e le prestazioni affidabili sono funzionalità comuni delle app web progressive. Anche in ambienti wireless perfetti, un uso corretto 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 di notizie e così via). Ma qual è la soluzione migliore? Quanto puoi archiviare? Come faccio a evitare che venga espulso?

Ecco un consiglio generale per l'archiviazione delle risorse:

IndexedDB, OPFS e l'API Cache Storage sono supportati in tutti i browser moderni. Sono asincroni e non bloccano il thread principale (ma esiste anche una variante sincrona dell'OPFS disponibile esclusivamente nei worker web). Sono accessibili dall'oggetto window, dai worker web e dai worker di servizio, il che consente di utilizzarli ovunque nel codice.

E per quanto riguarda altri meccanismi di archiviazione?

Esistono diversi altri meccanismi di archiviazione disponibili nel browser, ma hanno un utilizzo limitato e potrebbero causare problemi di prestazioni significativi.

SessionStorage è specifico per la scheda e limitato alla sua durata. Può essere utile per archiviare piccole quantità di informazioni specifiche di sessione, ad esempio una chiave IndexedDB. Deve essere utilizzato con cautela perché è sincrono e bloccherà il thread principale. È limitado a circa 5 MB e può contenere solo stringhe. Poiché è specifico per la scheda, non è accessibile da web worker o service worker.

LocalStorage deve essere evitato perché è sincrono e bloccherà il thread principale. Ha un limite di circa 5 MB e può contenere solo stringhe. LocalStorage non è accessibile da web worker o service worker.

I cookie hanno i propri scopi, ma non devono essere utilizzati per l'archiviazione. I cookie vengono inviati con ogni richiesta HTTP, pertanto la memorizzazione di più di una piccola quantità di dati aumenterà notevolmente le dimensioni di ogni richiesta web. Sono sincroni e non sono accessibili dai worker web. Come LocalStorage e SessionStorage, i cookie sono limitati alle sole stringhe.

L'API File System Access è stata progettata per consentire agli utenti di leggere e modificare i file sul file system locale. L'utente deve concedere l'autorizzazione prima che una pagina possa leggere o scrivere su qualsiasi file locale e le autorizzazioni non vengono rese persistenti 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 è necessario aprire un file, modificarlo e, eventualmente, salvare nuovamente le modifiche al file.

L'API File System e l'API FileWriter forniscono metodi per leggere e scrivere file in un file system sandbox. Sebbene sia asincrono, non è consigliato perché è disponibile solo nei browser basati su Chromium.

Quanto posso archiviare?

In breve, molto, almeno un paio di centinaia di megabyte e potenzialmente anche centinaia di gigabyte o più. Le implementazioni dei browser variano, ma la quantità di spazio di archiviazione disponibile in genere si basa 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à di navigazione in incognito, Chrome riduce la quantità di spazio di archiviazione che un'origine può utilizzare a circa il 5% dello spazio di 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 in modo significativo a un massimo di circa 300 MB.
  • Firefox consente al browser di utilizzare fino al 50% dello spazio libero su disco. Un gruppo eTLD+1 (ad es. example.com, www.example.com e foo.bar.example.com) può utilizzare fino a 2 GB. Puoi utilizzare l'API StorageManager per determinare quanto spazio è ancora disponibile.
  • Safari (sia su computer che su dispositivi mobili) sembra consentire circa 1 GB. Quando viene raggiunto il limite, Safari chiede all'utente di aumentare il limite in incrementi di 200 MB. Non sono riuscito a trovare documentazione ufficiale in merito.
    • Se una PWA viene aggiunta alla home page su Safari mobile, viene creato un nuovo contenitore di archiviazione e non viene condiviso nulla tra la PWA e Safari mobile. Una volta raggiunta la quota per una PWA installata, sembra non esserci modo di richiedere spazio di archiviazione aggiuntivo.

In passato, se un sito superava una determinata soglia di dati memorizzati, il browser chiedeva all'utente di concedere l'autorizzazione per l'utilizzo di più dati. Ad esempio, se l'origine ha utilizzato più di 50 MB, il browser chiede all'utente di consentire lo spazio di archiviazione fino a 100 MB, quindi chiede di nuovo con incrementi di 50 MB.

Oggi, la maggior parte dei browser moderni non chiederà all'utente e consentirà a un sito di utilizzare fino alla quota assegnata. L'eccezione sembra essere Safari, che ti avvisa quando la quota di spazio di archiviazione viene superata, richiedendo l'autorizzazione per aumentare la quota allocata. Se un'origine tenta di utilizzare più della quota assegnata, gli ulteriori tentativi di scrittura dei dati non andranno a buon fine.

Come faccio a verificare la quantità di 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 quanto spazio di archiviazione sta utilizzando. Indica 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 di seguito). In alcuni casi, è possibile che la quota disponibile superi la quantità effettiva di spazio di archiviazione disponibile.

Ispeziona

Durante lo sviluppo, puoi utilizzare gli strumenti per gli sviluppatori del browser per ispezionare i diversi tipi di archiviazione ed eliminare tutti i dati memorizzati.

In Chrome 88 è stata aggiunta una nuova funzionalità che ti consente di ignorare la quota di archiviazione del sito nel riquadro Spazio di archiviazione. Questa funzionalità ti consente di simulare diversi dispositivi e di testare il comportamento delle tue app in scenari di bassa disponibilità del disco. Vai a Applicazione, poi a Spazio di 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.

Mentre lavoravo a questa guida, ho scritto un semplice strumento per tentare di utilizzare rapidamente quanto più spazio di archiviazione possibile. È un modo rapido per sperimentare diversi meccanismi di archiviazione e vedere cosa succede quando utilizzi tutta la tua quota.

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 qualcos'altro. Poi, a seconda del design dell'app, decidi come gestirla. Ad esempio, elimina i contenuti a cui non è stato eseguito l'accesso da molto tempo, rimuovi i dati in base alle dimensioni o offri agli utenti un modo per scegliere cosa eliminare.

Sia IndexedDB che l'API Cache generano un DOMError denominato QuotaExceededError quando hai superato la quota disponibile.

IndexedDB

Se l'origine ha superato la quota, i tentativi di scrittura in IndexedDB non andranno a buon fine. Verrà chiamato il gestore onabort() della transazione, passando un evento. L'evento includerà un DOMException nella proprietà error. Se controlli l'errore name, viene restituito 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 DOMException QuotaExceededError.

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 è classificato in due bucket: "Miglior sforzo" e "Persistente". Best effort significa che lo spazio di archiviazione può essere cancellato dal browser senza interrompere l'utente, ma è meno duraturo per i dati critici o a lungo termine. Lo spazio di archiviazione permanente non viene cancellato automaticamente quando lo spazio è ridotto. L'utente deve cancellare manualmente questo spazio di archiviazione (tramite le impostazioni del browser).

Per impostazione predefinita, i dati di un sito (inclusi IndexedDB, API Cache e così via) rientrano nella categoria del massimo impegno, il che significa che, a meno che un sito non abbia richiesto uno spazio di archiviazione permanente, il browser può eliminare i dati del sito a sua discrezione, ad esempio quando lo spazio di archiviazione del dispositivo è basso.

Il criterio di espulsione per il criterio del massimo impegno è:

  • I browser basati su Chromium inizieranno a eliminare i dati quando lo spazio del browser sarà esaurito, cancellando prima tutti i dati del sito dell'origine utilizzata meno di recente, poi quelli della successiva, fino a quando il browser non supererà più il limite.
  • Firefox inizierà a eliminare i dati quando lo spazio su disco disponibile sarà esaurito, cancellando prima tutti i dati del sito dall'origine utilizzata meno di recente, poi dalla successiva, fino a quando il browser non supererà più il limite.
  • In precedenza, Safari non ha rimosso 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, è previsto un limite di sette giorni per tutto lo spazio di archiviazione dello script scrivibile, tra cui IndexedDB, la registrazione dei worker di servizio e l'API Cache. Ciò significa che Safari eliminerà tutti i contenuti dalla cache dopo sette giorni di utilizzo se l'utente non interagisce con il sito. Questo criterio di espulsione non si applica alle PWA installate che sono state aggiunte alla schermata Home. Per informazioni dettagliate, consulta Bloccare completamente i cookie di terze parti e altro ancora sul blog di WebKit.

Bucket di archiviazione

L'idea di base dell'API Storage Buckets è concedere ai siti la possibilità di creare più bucket di archiviazione, in cui il browser può scegliere di eliminare ogni bucket indipendentemente dagli altri. In questo modo gli sviluppatori possono specificare la priorità dell'espulsione 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 API moderne basate su promesse, è basata su eventi. I wrapper promessi come idb per IndexedDB nascondono alcune delle potenti funzionalità, ma soprattutto nascondono i macchinari complessi (ad es. transazioni, controllo delle versioni dello schema) inclusi nella libreria IndexedDB.

Bonus: SQLite Wasm

Dopo che SQL web è stato deprecato e rimosso da Chrome, Google ha collaborato con i gestori del popolare database SQLite per offrire un sostituto per il linguaggio SQL web basato su SQLite. Per informazioni dettagliate su come utilizzarlo, consulta 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. Con l'API StorageManager puoi determinare quanto spazio di archiviazione è a tua disposizione e quanto ne hai utilizzato. Inoltre, con lo spazio di archiviazione permanente, a meno che l'utente non lo rimuova, puoi proteggerlo dall'espulsione.

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. Eiji ha scritto uno strumento utile chiamato Browser Storage Abuser che è stato utile per convalidare il comportamento attuale. Ti consente di archiviare il maggior numero possibile di dati e di visualizzare i limiti di archiviazione sul browser. Grazie a François Beaufort che ha analizzato Safari per scoprire i suoi limiti di spazio 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 complessivo dei contenuti nel 2024.

L'immagine hero è di Guillaume Bolduc su Unsplash.