Spazio di archiviazione per il Web

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

Le connessioni a internet possono essere inesistenti o inefficaci ovunque ti trovi, ecco perché il supporto offline e le prestazioni affidabili sono caratteristiche comuni nelle app web progressive. Anche in ambienti wireless perfetti, l'uso oculato della memorizzazione nella cache e di altre tecniche di archiviazione può migliorare sostanzialmente 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 fai a evitare che venga espulsa?

Che cosa devo usare?

Ecco un suggerimento generale per l'archiviazione delle risorse:

IndexedDB e l'API Cache Storage sono supportati in tutti i browser moderni. Sono entrambi asincroni e non bloccano il thread principale. Sono accessibili dall'oggetto window, dai web worker e dai service worker, il che ne semplifica l'utilizzo in qualsiasi punto del codice.

E gli altri meccanismi di archiviazione?

Nel browser sono disponibili molti altri meccanismi di archiviazione, che però hanno un uso limitato e possono causare problemi di prestazioni significativi.

SessionStorage è specifico per le schede e ha come ambito la durata della scheda. Può essere utile per l'archiviazione di piccole quantità di informazioni specifiche per le sessioni, ad esempio una chiave IndexedDB. Deve essere usato con cautela perché è sincrono e bloccherà il thread principale. È limitato a circa 5 MB e può contenere solo stringhe. Poiché è specifica per una scheda, non è accessibile da web worker o service worker.

LocalStorage dovrebbe 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 worker.

I cookie hanno le loro finalità, ma non devono essere utilizzati per l'archiviazione. I cookie vengono inviati con ogni richiesta HTTP, pertanto l'archiviazione di qualsiasi cosa diversa da una piccola quantità di dati aumenterà notevolmente le dimensioni di ogni richiesta web. Sono sincroni e non sono accessibili dai web worker. Come LocalStorage e SessionStorage, i cookie sono limitati solo alle stringhe.

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

L'API File System Access è stata progettata per semplificare la lettura e la modifica dei file nel 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.

Non deve essere utilizzato WebSQL ed è necessario eseguire la migrazione dell'utilizzo esistente a IndexedDB. Il supporto è rimosso da quasi tutti i principali browser. Il W3C ha smesso di mantenere le specifiche Web SQL nel 2010, senza prevedere ulteriori aggiornamenti.

La cache dell'applicazione non deve essere utilizzata ed è necessario eseguire la migrazione dell'utilizzo esistente ai service worker e all'API Cache. È stato ritirato e il supporto verrà rimosso dai browser in futuro.

Quanto posso archiviare?

In breve, molti, almeno un paio di centinaia di megabyte e potenzialmente centinaia di gigabyte o più. Le implementazioni del browser variano, ma la quantità di spazio di archiviazione disponibile dipende solitamente dalla quantità di spazio di archiviazione disponibile sul dispositivo.

  • Chrome consente al browser di utilizzare fino all'80% dello spazio totale su disco. 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 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 in modo significativo fino a un massimo di circa 300 MB.
    • Consulta l'PR 3896 per i dettagli sull'implementazione di Chrome.
  • Internet Explorer 10 e versioni successive possono archiviare fino a 250 MB e richiedono all'utente quando sono stati utilizzati più di 10 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) possono utilizzare fino a 2 GB. Puoi utilizzare l'API StorageManager per determinare la quantità di spazio ancora disponibile.
  • Safari (sia desktop che mobile) sembra consentire circa 1 GB. Quando il limite viene raggiunto, Safari chiede all'utente di aumentare il limite con incrementi di 200 MB. Non ho trovato alcuna documentazione ufficiale in merito.
    • Se viene aggiunta una PWA alla schermata Home di Safari per dispositivi mobili, sembra creare 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 alcun modo per richiedere spazio di archiviazione aggiuntivo.

In passato, se un sito superava una determinata soglia di dati archiviati, il browser richiedeva all'utente di concedere l'autorizzazione a utilizzare più dati. Ad esempio, se l'origine utilizzava più di 50 MB, il browser chiedeva all'utente di archiviare fino a 100 MB e poi chiedeva di nuovo con incrementi di 50 MB.

Oggi, la maggior parte dei browser moderni non invia richieste all'utente e consente a un sito di utilizzare fino alla quota assegnata. L'eccezione sembra essere Safari, che visualizza un messaggio quando la quota di spazio di archiviazione viene superata, richiedendo l'autorizzazione per aumentare la quota allocata. Se un'origine tenta di utilizzare una quota superiore a quella assegnata, ulteriori tentativi di scrittura di dati non andranno a buon fine.

Come faccio a controllare 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 la quantità di spazio che sta utilizzando. Riporta il numero totale di byte utilizzati da IndexedDB e dall'API Cache e consente di calcolare approssimativamente lo spazio di archiviazione rimanente 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.`);
}

StorageManager non è ancora implementato in tutti i browser, quindi devi rilevarlo dalla funzionalità prima di utilizzarlo. Anche quando è disponibile, devi comunque 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 i DevTools del browser per esaminare i diversi tipi di archiviazione e cancellare facilmente tutti i dati archiviati.

In Chrome 88 è stata aggiunta una nuova funzionalità che consente di sostituire la quota di archiviazione del sito nel riquadro di archiviazione. Questa funzionalità consente di simulare diversi dispositivi e di testare il comportamento delle app in scenari di bassa disponibilità del disco. Vai ad Applicazione, quindi Spazio di archiviazione, abilita la casella di controllo Simula quota di archiviazione personalizzata e inserisci un numero valido per simulare la quota di archiviazione.

Riquadro Archiviazione DevTools.

Mentre lavoravo a questo articolo, ho scritto un semplice strumento per tentare di utilizzare rapidamente la maggiore quantità di spazio di archiviazione possibile. È un modo semplice e veloce 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 disponibile? In particolare, dovresti sempre rilevare e gestire gli errori di scrittura, che si tratti di QuotaExceededError o di qualcos'altro. Quindi, a seconda del design dell'app, decidi come gestirlo. Ad esempio, elimina i contenuti che non vengono consultati da molto tempo, rimuovi i dati in base alle dimensioni o fornisci agli utenti un modo per scegliere quali dati eliminare.

Sia IndexedDB che l'API Cache generano entrambi un DOMError denominato QuotaExceededError quando superi 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, che trasmette un evento. L'evento includerà un DOMException nella proprietà dell'errore. La selezione 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 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?

L'archiviazione web è classificata in due bucket, "Best Effort" e "Persistent". Best effort significa che lo spazio di archiviazione può essere cancellato dal browser senza interrompere l'utente, ma è meno durevole per dati critici o a lungo termine. L'archiviazione permanente non viene cancellata 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 (inclusi 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 di archiviazione del dispositivo è in esaurimento.

Le norme di rimozione per il massimo impegno sono:

  • I browser basati su Chromium inizieranno a rimuovere i dati quando il browser esaurisce lo spazio, cancellando tutti i dati del sito dall'origine utilizzata meno di recente e poi dall'origine successiva, finché il browser non supererà più il limite.
  • Internet Explorer 10 e versioni successive non rimuoverà i dati, ma impedirà all'origine di scrivere più.
  • Firefox inizierà a rimuovere i dati quando lo spazio su disco disponibile è esaurito, cancellando tutti i dati del sito dall'origine meno recente utilizzata e poi dall'origine successiva, fino a quando il browser non supera più il limite.
  • In precedenza Safari non ha rimosso i dati, ma di recente ha implementato un nuovo limite di sette giorni su 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 su tutto l'archiviazione scrivibile di script, tra cui IndexedDB, registrazione dei worker di servizio 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. Questo criterio di rimozione non si applica alle PWA installate che sono state aggiunte alla schermata Home. Per informazioni dettagliate, consulta Blocco completo dei cookie di terze parti e altro ancora sul blog di WebKit.

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 semplici. Diversamente dalla maggior parte delle moderne API basate su promise, I wrapper Promise 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.

Conclusione

Sono finiti i tempi dello spazio di archiviazione limitato e della necessità di archiviare sempre più dati. I siti possono archiviare in modo efficace tutte le risorse e i dati di cui hanno bisogno per eseguire. Utilizzando l'API StorageManager puoi determinare quanto hai a disposizione e quanto hai utilizzato. Inoltre, grazie all'archiviazione permanente, puoi proteggerla dall'eliminazione, a meno che l'utente non la rimuove.

Altre risorse

Grazie per aver deciso

Un ringraziamento speciale a Jarryd Goodman, Phil Walton, Eiji Kitamura, Daniel Murphy, Darwin Huang, Josh Bell, Marijn Kruisselbrink e Victor Costan per aver letto questo articolo. Grazie a Eiji Kitamura, Addy Osmani e Marc Cohen che hanno scritto gli articoli originali su cui si basa. Eiji ha scritto un utile strumento, chiamato Browser Storage Abuser, che si è rivelato utile per convalidare il comportamento attuale. Consente di archiviare il maggior numero possibile di dati e di vedere i limiti di spazio di archiviazione del browser. Grazie a Francois Beaufort che ha scavato in Safari per capire i limiti dello spazio di archiviazione.

L'immagine hero è di Guillaume Bolduc su Unsplash.