JavaScript IndexedDB
JavaScript IndexedDB: Datenbank öffnen, onupgradeneeded behandeln, Object Stores und Indexes erstellen, Transaktionen ausführen sowie Datensätze hinzufügen, abrufen, aktualisieren und löschen.
IndexedDB ist eine leistungsstarke clientseitige Speicher-API, die robuster ist als andere lokale Speicherlösungen in Webbrowsern. Sie ermöglicht es Webanwendungen, erhebliche Mengen strukturierter Daten asynchron zu speichern und zu verarbeiten. IndexedDB eignet sich hervorragend für Anwendungen, die Offline-Datenspeicherung, hohe Leistung und umfangreiche Abfragemöglichkeiten ohne Netzwerkverbindung benötigen.
Dieses Kapitel behandelt alles, was Sie für den Einstieg in IndexedDB benötigen: das Öffnen einer Datenbank und das Verarbeiten von Versions-Upgrades, das Erstellen von Object Stores und Indexes, das Ausführen von Transaktionen sowie den vollständigen CRUD-Zyklus (Hinzufügen, Abrufen, Aktualisieren, Löschen) einschließlich der Iteration mit Cursors und der Abfrage über Indexes.
Wann sollte IndexedDB verwendet werden?
IndexedDB speichert nahezu jeden JavaScript-Wert — Objekte, arrays, Datumsangaben, Blobs und Dateien — nicht nur strings, und kann Hunderte von Megabytes aufnehmen, weit über das ~5-MB-Limit von localStorage und sessionStorage hinaus. Es handelt sich um einen transaktionalen NoSQL-Key/Value-Speicher mit Indexes, der die richtige Wahl ist für:
- Offline-First-Apps, die ohne Netzwerkverbindung funktionieren müssen.
- Caching großer Datensätze wie API-Antworten, Dokumente oder Mediendateien.
- Abfragen von Datensätzen über indizierte Felder, anstatt alles in den Arbeitsspeicher zu laden.
Wenn Sie nur wenige kleine string-Werte persistieren müssen, greifen Sie stattdessen auf die einfacheren Web Storage APIs zurück. Im Kapitel über die Storage API finden Sie einen Überblick darüber, wie der Browser Speicherkontingente über diese Mechanismen hinweg verwaltet.
Die ereignisbasierte, asynchrone API
Jede IndexedDB-Operation ist asynchron und ereignisgesteuert. Aufrufe wie indexedDB.open() oder store.get() geben sofort ein Request-Objekt zurück; das eigentliche Ergebnis kommt später über onsuccess- / onerror-Ereignishandler. Ihr Code blockiert niemals beim Warten auf Festplatten-I/O. Aus diesem Grund können Sie ein Ergebnis nicht synchron direkt nach dem Ausstellen einer Anfrage lesen — Sie müssen warten, bis das Ereignis ausgelöst wird. (Moderner Code kapselt diese Requests oft in Promises, aber die native API selbst ist callback-basiert, was die nachfolgenden Beispiele verwenden.)
Eine IndexedDB-Datenbank einrichten
Schritt 1: Eine Datenbank öffnen
Um IndexedDB zu verwenden, öffnen Sie zunächst eine Datenbank mit indexedDB.open(name, version). Das optionale zweite Argument ist eine ganzzahlige Versionsnummer. Wenn die Datenbank nicht existiert oder die angeforderte Version höher ist als die gespeicherte, wird das Ereignis onupgradeneeded ausgelöst — dies ist der einzige Ort, an dem Sie die Datenbankstruktur ändern dürfen (Object Stores und Indexes erstellen oder löschen).
Der Aufruf gibt einen Request zurück und kann drei Ereignisse auslösen:
onsuccess— die Datenbank wurde geöffnet und ist bereit (event.target.resultist dieIDBDatabase).onerror— das Öffnen ist fehlgeschlagen.onupgradeneeded— eine Schemaänderung ist erforderlich (siehe Schritt 2).
Hier sehen Sie, wie Sie eine IndexedDB-Datenbank erstellen oder öffnen können. Nach einem erfolgreichen Vorgang schließen wir die Datenbank, um unerwünschte Nebeneffekte in anderen Beispielen zu vermeiden. In Ihrem eigenen Code können Sie diesen Schritt überspringen oder bei Bedarf einschließen.
Warnung: Der Aufruf von deleteDatabase() löscht alle Daten dieser Datenbank. Dies dient nur zu Testzwecken und sollte nicht in der Produktion verwendet werden.
Schritt 2: Object Stores erstellen
Sobald die Datenbank geöffnet ist, können Sie einen Object Store erstellen, der einer Tabelle in relationalen Datenbanken ähnelt. Beachten Sie, dass dies nur während eines Versions-Upgrades möglich ist (wenn die Datenbank mit einer höheren Versionsnummer geöffnet wird). Das zu überwachende Ereignis ist onupgradeneeded.
Beim Erstellen eines Stores legen Sie fest, wie der Primärschlüssel jedes Datensatzes definiert wird:
{ keyPath: 'id' }— der Schlüssel wird aus derid-Eigenschaft jedes gespeicherten Objekts gelesen (ein Inline-Schlüssel).{ keyPath: 'id', autoIncrement: true }— der Store generiert automatisch einen sequenziellen Schlüssel, wenn keiner angegeben wird.{ autoIncrement: true }— Schlüssel werden generiert und getrennt vom Wert gespeichert (ein Out-of-Line-Schlüssel).
Sie erstellen auch Indexes innerhalb von onupgradeneeded. Ein Index ermöglicht es, Datensätze über eine andere Eigenschaft als den Primärschlüssel zu suchen. Übergeben Sie { unique: true }, um doppelte Werte für diese Eigenschaft abzulehnen.
Transaktionen
Sobald Ihre Datenbank und Object Stores eingerichtet sind, müssen Sie Datenoperationen mithilfe von Transaktionen verwalten. Eine Transaktion in IndexedDB ist ein Mechanismus, der mehrere Operationen zu einer einzigen Arbeitseinheit zusammenfasst, die entweder vollständig erfolgreich ist oder vollständig fehlschlägt. Sie ist wesentlich für die Gewährleistung von Datenkonsistenz und -integrität, insbesondere wenn mehrere Operationen voneinander abhängen, um ein korrektes Ergebnis zu erzielen.
Transaktionen in IndexedDB verwenden
Schritt 1: Eine Transaktion starten
Um eine Operation in IndexedDB durchzuführen, beginnen Sie mit dem Erstellen einer Transaktion auf einer Datenbank. Eine Transaktion wird erstellt, indem angegeben wird, welche Object Stores die Transaktion betrifft und welchen Modus die Transaktion hat: entweder "readonly" oder "readwrite".
Schritt 2: Auf einen Object Store zugreifen
Innerhalb einer Transaktion können Sie auf einen oder mehrere Object Stores zugreifen, um Datenoperationen durchzuführen.
Schritt 3: Operationen durchführen
Sobald Sie Zugriff auf einen Object Store haben, können Sie verschiedene Operationen ausführen, wie das Hinzufügen, Abrufen, Aktualisieren oder Löschen von Daten. Jede Operation gibt ein Request-Objekt zurück, das Sie zur Behandlung von Erfolgs- oder Fehlerereignissen verwenden können.
Schritt 4: Die Transaktion abschließen
Eine Transaktion wird automatisch abgeschlossen, sobald alle darin ausgestellten Operationen aufgelöst wurden, entweder durch Erfolg oder Misserfolg. Sie können auch auf das complete-Ereignis der Transaktion warten, um Aktionen nach dem erfolgreichen Abschluss aller Operationen auszuführen.
Hier ist ein Beispiel einer vollständigen Transaktion:
Daten lesen
Um Daten abzurufen, verwenden Sie store.get(key) oder einen Cursor zum Iterieren über mehrere Datensätze. Hier sind kurze Beispiele:
Einen einzelnen Datensatz abrufen:
Mit einem Cursor iterieren:
Abfragen mit Indexes
Mit dem Primärschlüssel können Sie einen Datensatz abrufen, wenn Sie seinen Schlüssel bereits kennen. Ein Index ermöglicht die Suche nach einer anderen Eigenschaft — beispielsweise das Finden eines Buches anhand seines title. Greifen Sie mit store.index(name) auf einen Index zu und rufen Sie dann darauf get(), getAll() oder openCursor() auf, genau wie bei einem Store.
Einen Datensatz über eine indizierte Eigenschaft suchen:
Sie können eine Abfrage auch auf einen Schlüsselbereich mit IDBKeyRange einschränken (zum Beispiel IDBKeyRange.bound('A', 'M'), um alle Bücher abzurufen, deren Titel zwischen A und M beginnt), indem Sie den Bereich an getAll() oder openCursor() übergeben.
Datensätze aktualisieren und löschen
Um vorhandene Daten zu ändern, verwenden Sie store.put() mit demselben Schlüssel. Um Daten zu entfernen, verwenden Sie store.delete(key).
Einen Datensatz aktualisieren:
Einen Datensatz löschen:
IndexedDB-Inhalte im Browser anzeigen
Nachdem Sie Daten gespeichert und verarbeitet haben, möchten Sie möglicherweise überprüfen, was tatsächlich in Ihrem Browser gespeichert ist. Die meisten modernen Browser zeigen an, was in IndexedDB gespeichert ist. Nachfolgend ein Beispiel aus den Entwicklertools von Chrome:

Best Practices für die Verwendung von Transaktionen
Um sicherzustellen, dass Ihre IndexedDB-Implementierung zuverlässig und leistungsfähig bleibt, befolgen Sie diese Richtlinien:
- Umfang minimieren: Halten Sie Transaktionen so klein wie möglich, sowohl hinsichtlich der Anzahl der Operationen als auch der Dauer. Dies verringert die Wahrscheinlichkeit von Konflikten und verbessert die Leistung.
- Fehlerbehandlung: Implementieren Sie immer eine Fehlerbehandlung sowohl auf der Request- als auch auf der Transaktionsebene. Dies hilft bei der Diagnose von Problemen und verhindert partielle Aktualisierungen, die zu Datenbeschädigung führen könnten.
- Parallelität: Beachten Sie, dass Transaktionen auf derselben Datenbank in der Warteschlange stehen und seriell ausgeführt werden, obwohl IndexedDB asynchron und nicht-blockierend ist, um Datenwettläufe und Inkonsistenzen zu verhindern.
Fazit
IndexedDB bietet eine robuste Plattform für komplexes Datenmanagement in Webanwendungen und ist damit ein unverzichtbares Werkzeug für moderne Webentwickler. Durch die ordnungsgemäße Implementierung seiner Funktionen können Entwickler clientseitige Daten effizient speichern, abrufen, aktualisieren und löschen, was die Anwendungsleistung und die Benutzererfahrung verbessert.
Für einfachere Speicheranforderungen und um ein besseres Verständnis des Browser-Speicher-Gesamtbilds zu erhalten, lesen Sie diese verwandten Kapitel:
- localStorage und sessionStorage — leichtgewichtige Key/Value-Speicherung für kleine Mengen von string-Daten.
- Die Storage API — wie der Browser Speicherkontingente und Persistenz über verschiedene Mechanismen hinweg verwaltet.
- Arbeiten mit JSON — Serialisierung von Daten, nützlich beim Verschieben von Objekten in und aus dem Speicher.