Speicherplatz für das Web

Es gibt viele verschiedene Optionen zum Speichern von Daten im Browser. Welche Funktion ist für Ihre Anforderungen am besten geeignet?

Internetverbindungen können unterwegs instabil oder nicht vorhanden sein. Daher sind Offlinesupport und zuverlässige Leistung gängige Features in Progressive Web-Apps. Selbst in perfekten drahtlosen Umgebungen kann der vernünftige Einsatz von Caching und anderen Speichertechniken die Nutzererfahrung erheblich verbessern. Es gibt mehrere Möglichkeiten, Ihre statischen Anwendungsressourcen (HTML, JavaScript, CSS, Bilder usw.) und Daten (Nutzerdaten, Nachrichtenartikel usw.) im Cache zu speichern. Aber welche ist die beste Lösung? Wie viel können Sie speichern? Wie verhindern Sie, dass die Inhalte gelöscht werden?

Was sollte ich verwenden?

Hier ist eine allgemeine Empfehlung zum Speichern von Ressourcen:

IndexedDB und die Cache Storage API werden von jedem modernen Browser unterstützt. Sie sind beide asynchron und blockieren nicht den Hauptthread. Sie sind über das Objekt window, Web Worker und Service Worker zugänglich, sodass Sie sie überall im Code einfach verwenden können.

Wie sieht es mit anderen Speichermechanismen aus?

Im Browser sind mehrere andere Speichermechanismen verfügbar, die jedoch nur eingeschränkt verwendet werden und zu erheblichen Leistungsproblemen führen können.

SessionStorage ist tabulatorspezifisch und beschränkt sich auf die Lebensdauer des Tabs. Dies kann nützlich sein, um kleine Mengen sitzungsspezifischer Informationen zu speichern, z. B. einen IndexedDB-Schlüssel. Sie sollte mit Vorsicht verwendet werden, da sie synchron ist und den Hauptthread blockiert. Es ist auf etwa 5 MB begrenzt und darf nur Strings enthalten. Da sie tabulatorspezifisch ist, können Web Worker oder Service Worker nicht darauf zugreifen.

LocalStorage sollte vermieden werden, da es synchron ist und den Hauptthread blockiert. Es ist auf etwa 5 MB beschränkt und darf nur Strings enthalten. LocalStorage ist für Web-Worker oder Service-Worker nicht zugänglich.

Cookies haben ihre Verwendungszwecke, sollten aber nicht zum Speichern genutzt werden. Cookies werden mit jeder HTTP-Anfrage gesendet. Wenn also mehr als eine kleine Datenmenge gespeichert werden, erhöht sich die Größe jeder Webanfrage erheblich. Sie sind synchron und können von Web Workern nicht aufgerufen werden. Wie LocalStorage und SessionStorage sind Cookies auf Strings beschränkt.

Die File System API und die FileWriter API bieten Methoden zum Lesen und Schreiben von Dateien in ein Sandbox-Dateisystem. Obwohl es asynchron ist, wird es nicht empfohlen, da es nur in Chromium-basierten Browsern verfügbar ist.

Die File System Access API wurde entwickelt, um Nutzern das Lesen und Bearbeiten von Dateien in ihrem lokalen Dateisystem zu erleichtern. Der Nutzer muss die Berechtigung erteilen, bevor eine Seite in einer lokalen Datei lesen oder schreiben kann. Außerdem werden Berechtigungen nicht sitzungsübergreifend beibehalten.

WebSQL sollte nicht verwendet werden und vorhandene Nutzung sollte zu IndexedDB migriert werden. Fast alle gängigen Browser werden nicht mehr unterstützt. Das W3C hat die Pflege der Web SQL-Spezifikation 2010 eingestellt. Weitere Updates sind nicht geplant.

Der Application Cache sollte nicht verwendet werden. Bestehende Nutzung sollte zu Service Workern und zur Cache API migriert werden. Sie wurde eingestellt und wird in zukünftigen Browsern nicht mehr unterstützt.

Wie viel kann ich speichern?

Kurz gesagt, unverzüglich, mindestens einige hundert Megabyte und potenziell mehrere hundert Gigabyte oder mehr. Browserimplementierungen variieren, aber wie viel Speicherplatz noch verfügbar ist, hängt von der Menge des auf dem Gerät verfügbaren Speichers ab.

  • Mit Chrome kann der Browser bis zu 80% des gesamten Speicherplatzes belegen. Ein Ursprung kann bis zu 60% des gesamten Speicherplatzes nutzen. Sie können die StorageManager API verwenden, um das maximal verfügbare Kontingent zu ermitteln. Andere Chromium-basierte Browser können anders sein.
    • Im Inkognitomodus reduziert Chrome den Speicherplatz, den ein Ursprung verwenden kann, auf etwa 5% des gesamten Speicherplatzes.
    • Wenn der Nutzer die Option „Cookies und Websitedaten beim Schließen aller Fenster löschen“ in Chrome aktiviert hat, wird das Speicherkontingent erheblich auf maximal etwa 300 MB reduziert.
    • Einzelheiten zur Implementierung von Chrome findest du unter PR 3896.
  • Internet Explorer 10 und höher kann bis zu 250 MB speichern. Der Nutzer wird benachrichtigt, wenn mehr als 10 MB belegt sind.
  • Bei Firefox kann der Browser bis zu 50% des freien Speicherplatzes belegen. Eine eTLD+1-Gruppe (z.B. example.com, www.example.com und foo.bar.example.com) können bis zu 2 GB belegen. Mit der StorageManager API können Sie feststellen, wie viel Speicherplatz noch verfügbar ist.
  • In Safari (sowohl auf dem Desktop als auch auf Mobilgeräten) sind offenbar etwa 1 GB Speicherplatz belegt. Wenn das Limit erreicht ist, wird der Nutzer in Safari dazu aufgefordert, das Limit in Schritten von 200 MB zu erhöhen. Ich konnte dazu keine offizielle Dokumentation finden.
    • Wenn eine PWA dem Startbildschirm in der mobilen Version von Safari hinzugefügt wird, wird als neuer Speichercontainer ein neuer Speichercontainer erstellt. Von der PWA und mobilen Safari wird nichts gemeinsam verwendet. Wenn das Kontingent für eine installierte PWA erreicht ist, gibt es offenbar keine Möglichkeit mehr, zusätzlichen Speicherplatz anzufordern.

Wenn eine Website in der Vergangenheit einen bestimmten Schwellenwert der gespeicherten Daten überschritten hat, hat der Browser den Nutzer aufgefordert, die Berechtigung zu erteilen, mehr Daten zu verwenden. Wenn der Ursprung beispielsweise mehr als 50 MB verwendet hat, fordert der Browser den Nutzer auf, bis zu 100 MB zu speichern. Anschließend wird die Anfrage in Schritten von 50 MB noch einmal abgefragt.

Heutzutage werden Nutzer von den meisten modernen Browsern keine Aufforderung erhalten und Websites erlauben, das ihr zugewiesene Kontingent vollständig zu nutzen. Die Ausnahme scheint Safari zu sein. Wenn das Speicherkontingent überschritten wird, wird eine Berechtigung zum Erhöhen des zugewiesenen Kontingents angefordert. Wenn ein Ursprung versucht, das zugewiesene Kontingent zu überschreiten, schlagen weitere Versuche fehl, Daten zu schreiben.

Wie finde ich heraus, wie viel Speicherplatz verfügbar ist?

In vielen Browsern können Sie mit der StorageManager API ermitteln, wie viel Speicherplatz für den Ursprung verfügbar ist und wie viel Speicherplatz genutzt wird. Sie meldet die Gesamtzahl der von IndexedDB und der Cache API verwendeten Byte und macht es möglich, den ungefähren verbleibenden Speicherplatz zu berechnen.

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.`);
}

Der StorageManager wurde noch nicht in allen Browsern implementiert. Daher muss er vor der Verwendung von einer Funktion erkannt werden. Auch wenn es verfügbar ist, müssen Sie dennoch Kontingentüberschreitungen erkennen (siehe unten). In einigen Fällen kann es vorkommen, dass das verfügbare Kontingent die tatsächlich verfügbare Speichermenge übersteigt.

Prüfen

Während der Entwicklung können Sie die Entwicklertools Ihres Browsers verwenden, um die verschiedenen Speichertypen zu prüfen und alle gespeicherten Daten einfach zu löschen.

In Chrome 88 wurde eine neue Funktion hinzugefügt, mit der Sie das Speicherkontingent der Website im Speicherbereich überschreiben können. Mit diesem Feature können Sie verschiedene Geräte simulieren und das Verhalten Ihrer Anwendungen in Szenarien mit geringer Laufwerksverfügbarkeit testen. Gehen Sie zu Anwendung und dann zu Speicher, aktivieren Sie das Kästchen Benutzerdefiniertes Speicherkontingent simulieren und geben Sie eine gültige Zahl ein, um das Speicherkontingent zu simulieren.

Entwicklertools-Speicher.

Für die Arbeit an diesem Artikel habe ich ein einfaches Tool geschrieben, das versuchen soll, schnell so viel Speicherplatz wie möglich zu nutzen. So können Sie schnell und einfach mit verschiedenen Speichermechanismen experimentieren und sehen, was passiert, wenn Sie Ihr gesamtes Kontingent ausschöpfen.

Wie gehe ich mit einer Überschreitung des Kontingents um?

Was sollten Sie tun, wenn Sie das Kontingent überschreiten? Am wichtigsten ist, dass Sie Schreibfehler immer erkennen und verarbeiten, egal ob es sich um QuotaExceededError oder etwas anderes handelt. Entscheiden Sie dann je nach App-Design, wie Sie damit umgehen möchten. Sie können beispielsweise Inhalte löschen, auf die lange nicht mehr zugegriffen wurde, Daten basierend auf der Größe entfernen oder Nutzern die Möglichkeit geben, selbst auszuwählen, was sie löschen möchten.

Sowohl IndexedDB als auch die Cache API geben eine DOMError mit dem Namen QuotaExceededError aus, wenn Sie das verfügbare Kontingent überschritten haben.

IndexedDB

Wenn der Ursprung das Kontingent überschritten hat, schlagen Schreibversuche in IndexedDB fehl. Der onabort()-Handler der Transaktion wird aufgerufen und dabei ein Ereignis übergeben. Das Ereignis enthält im Attribut „Fehler“ den Wert „DOMException“. Beim Prüfen des Fehlers name wird QuotaExceededError zurückgegeben.

const transaction = idb.transaction(['entries'], 'readwrite');
transaction.onabort = function(event) {
  const error = event.target.error; // DOMException
  if (error.name == 'QuotaExceededError') {
    // Fallback code goes here
  }
};

Cache-API

Wenn der Ursprung das Kontingent überschritten hat, werden Schreibversuche in die Cache API mit einem QuotaExceededError-DOMException abgelehnt.

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
  }
}

Wie funktioniert die Bereinigung?

Webspeicher wird in zwei Kategorien unterteilt: „Best Effort“ und „Persistent“. Bestmöglich bedeutet, dass der Speicher vom Browser gelöscht werden kann, ohne den Nutzer zu unterbrechen, aber für langfristige oder kritische Daten weniger langlebig ist. Nichtflüchtiger Speicher wird nicht automatisch gelöscht, wenn nur noch wenig Speicherplatz vorhanden ist. Der Nutzer muss diesen Speicher über die Browsereinstellungen manuell löschen.

Standardmäßig fallen die Daten einer Website (einschließlich IndexedDB, Cache API usw.) in die Best-Effort-Kategorie. Das bedeutet, dass der Browser Websitedaten nach eigenem Ermessen entfernen kann, wenn eine Website keinen nichtflüchtigen Speicher angefordert hat, z. B. wenn nur noch wenig Gerätespeicher verfügbar ist.

Die Richtlinie zur Bereinigung nach bestem Wissen und Gewissen lautet:

  • Chromium-basierte Browser beginnen mit dem Entfernen von Daten, wenn der Speicherplatz des Browsers ausgeht. Dabei werden zuerst alle Websitedaten vom am wenigsten verwendeten Ursprung gelöscht, dann von dem nächsten, bis der Browser das Limit nicht mehr überschreitet.
  • Internet Explorer 10+ entfernt keine Daten, verhindert jedoch, dass der Ursprung mehr geschrieben wird.
  • Firefox beginnt damit, Daten zu entfernen, sobald der verfügbare Speicherplatz voll ist. Dabei werden zuerst alle Websitedaten vom am wenigsten verwendeten Ursprung gelöscht, dann vom Ursprung, bis der Browser das Limit nicht mehr überschreitet.
  • Safari hat zuvor keine Daten entfernt, hat aber kürzlich eine neue Beschränkung von sieben Tagen für den gesamten beschreibbaren Speicher eingeführt (siehe unten).

Ab iOS und iPadOS 13.4 sowie Safari 13.1 unter macOS gilt eine Beschränkung auf sieben Tage für den beschreibbaren Speicher von Skripts, einschließlich IndexedDB, Service-Worker-Registrierung und Cache API. Das bedeutet, dass Safari alle Inhalte nach sieben Tagen nach Nutzung von Safari aus dem Cache entfernt, wenn der Nutzer nicht mit der Website interagiert. Diese Richtlinie zur Bereinigung gilt nicht für installierte PWAs, die dem Startbildschirm hinzugefügt wurden. Ausführliche Informationen finden Sie unter Full Drittanbieter Cookie Blocking and More im WebKit-Blog.

Bonus: Vorteile eines Wrappers für IndexedDB

IndexedDB ist eine Low-Level-API, die vor der Verwendung aufwendig eingerichtet werden muss, was besonders zum Speichern einfacher Daten mühsam sein kann. Im Gegensatz zu den meisten modernen Promise-basierten APIs ist sie ereignisbasiert. Promise-Wrapper wie idb für IndexedDB verstecken einige der leistungsstarken Features, aber vor allem auch die komplexen Maschinen (z.B. Transaktionen, Schemaversionsverwaltung), die in der IndexedDB-Bibliothek enthalten sind.

Fazit

Die Tage mit dem begrenzten Speicherplatz, durch die Nutzer immer mehr Daten speichern müssen, sind vorbei. Websites können alle für die Ausführung erforderlichen Ressourcen und Daten effektiv speichern. Mit der StorageManager API können Sie ermitteln, wie viel Ihnen zur Verfügung steht und wie viel Sie verwendet haben. Und mit nichtflüchtigem Speicher können Sie ihn vor einer Bereinigung schützen, sofern der Nutzer ihn nicht entfernt.

Zusätzliche Ressourcen

Viele Grüße

Wir danken Jarryd Goodman, Phil Walton, Eiji Kitamura, Daniel Murphy, Darwin Huang, Josh Bell, Marijn Kruisselbrink und Victor Costan für die Lesen dieses Artikels. Wir danken Eiji Kitamura, Addy Osmani und Marc Cohen, die die Artikel verfasst haben, auf denen die Inhalte basieren. Eiji hat ein hilfreiches Tool namens Browser Storage Abuser geschrieben, mit dem sich das aktuelle Verhalten validieren lässt. Damit können Sie so viele Daten wie möglich speichern und die Speicherlimits in Ihrem Browser sehen. Vielen Dank an Francois Beaufort, der sich mit Safari auseinandersetzte, um die Speicherplatzbegrenzungen zu ermitteln.

Das Hero-Image stammt von Guillaume Bolduc auf Unsplash.