Das Erstellen von Anwendungen, die nahtlos offline funktionieren, ist zu einer Schlüsselanforderung in der modernen Webentwicklung geworden. IndexedDB bietet eine leistungsstarke Lösung für Entwickler, die große Datenmengen direkt im Browser speichern und verwalten möchten. Diese clientseitige NoSQL-Datenbank ermöglicht eine effiziente Datenverarbeitung und ist somit ideal für Webanwendungen, die eine Offline-Funktionalität benötigen. In diesem Artikel werden wir die Grundlagen von IndexedDB, seine wichtigsten Funktionen, untersuchen und Sie durch die Schritte zur Einrichtung und Verwendung in Ihren Webprojekten führen.
Was ist IndexedDB?
IndexedDB ist eine leistungsstarke clientseitige NoSQL-Datenbank, die es Webanwendungen ermöglicht, strukturierte Daten direkt im Browser zu speichern und zu verwalten. Es bietet eine effiziente Lösung für die Verarbeitung großer Datensätze lokal und ist somit ideal für Offline-Funktionalität und datenintensive Anwendungen.

Einer der Hauptvorteile von IndexedDB ist die Fähigkeit, Offline-Webanwendungen zu unterstützen. Es ermöglicht Entwicklern, erhebliche Datenmengen zu speichern, Indizierung für schnelles Abrufen zu verwenden, Transaktionen zu verwalten und Daten mithilfe von Cursorn zu navigieren. Diese Funktionen machen es zu einer ausgezeichneten Wahl für die Verarbeitung komplexer Daten in Web-Apps.
Die meisten modernen Webbrowser, einschließlich Chrome, Firefox, Safari und Edge, unterstützen IndexedDB. Es ist jedoch wichtig sicherzustellen, dass die Version von IndexedDB mit dem Browser kompatibel ist, den Sie für Ihre Webanwendung verwenden.
Um mit der Verwendung von IndexedDB zu beginnen, besteht der erste Schritt darin, eine Verbindung zur Datenbank zu öffnen, die zum Erstellen und Interagieren mit ihr erforderlich ist.

Erste Schritte mit IndexedDB: Ein umfassender Leitfaden
IndexedDB ist eine leistungsstarke clientseitige Speicherlösung für Webanwendungen. Dieser Leitfaden führt Sie durch alles, von der grundlegenden Einrichtung bis hin zu fortgeschrittenen Techniken und der praktischen Umsetzung.
Einrichten von IndexedDB
Erstellen und Öffnen einer Datenbank
Um eine neue Datenbank in IndexedDB zu erstellen, verwenden Sie die Methode indexedDB.open()
:
const request = indexedDB.open("MyDatabase", 1);
request.onupgradeneeded = (event) => {
const db = event.target.result;
// Create object stores and indexes here
};
Die Methode nimmt zwei Parameter entgegen: den Datenbanknamen und die Versionsnummer. Um eine bestehende Datenbank zu öffnen, können Sie die Methode einfach aufrufen, ohne eine Versionsnummer anzugeben.
Datenbank-Versioning
IndexedDB unterstützt die Versionierung, um Schemaänderungen zu verarbeiten. Wenn Sie eine Datenbank mit einer höheren Versionsnummer als der vorhandenen öffnen, wird das Ereignis onupgradeneeded
ausgelöst, sodass Sie Ihr Datenbankschema aktualisieren können.
Erstellen von Objektspeichern und Indizes
Objektspeicher sind Container für Ihre Daten in IndexedDB:
request.onupgradeneeded = (event) => {
const db = event.target.result;
// Create an object store with a key path
const objectStore = db.createObjectStore("customers", { keyPath: "id" });
// Create an index for efficient querying
objectStore.createIndex("name", "name", { unique: false });
};
Arbeiten mit Transaktionen
Grundlagen von Transaktionen verstehen
Transaktionen in IndexedDB wahren die Datenintegrität, indem sie mehrere Operationen in einer einzigen, atomaren Einheit gruppieren. Sie stellen sicher, dass entweder alle Änderungen angewendet werden oder keine.
Erstellen und Verwalten von Transaktionen
const transaction = db.transaction(["customers"], "readwrite");
const objectStore = transaction.objectStore("customers");
transaction.oncomplete = (event) => {
console.log("Transaction completed successfully");
};
transaction.onerror = (event) => {
console.error("Transaction failed");
};
Fehlerbehandlung und Rollback
Wenn eine Operation fehlschlägt, können Sie die Methode abort()
verwenden, um die gesamte Transaktion zurückzusetzen:
try {
// Perform operations
} catch (error) {
transaction.abort();
console.error("Transaction aborted:", error);
}
Datenoperationen in IndexedDB
Hinzufügen von Daten
const customerData = { id: "00001", name: "John Doe", email: "john@example.com" };
const request = objectStore.add(customerData);
request.onsuccess = (event) => {
console.log("Data added successfully");
};
Abrufen von Daten
Grundlegender Datenabruf nach Schlüssel:
const request = objectStore.get("00001");
request.onsuccess = (event) => {
console.log("Customer data:", request.result);
};
Filtern mit Indizes
const index = objectStore.index("name");
const request = index.get("John Doe");
request.onsuccess = (event) => {
console.log("Found by name:", request.result);
};
Erweiterte Abfragemethoden
Für komplexe Abfragen bietet IndexedDB Bereichsabfragen und zusammengesetzte Abfragen mithilfe von Methoden wie openCursor()
und IDBKeyRange
:
const range = IDBKeyRange.bound("A", "F"); // Names starting with A through F
const request = index.openCursor(range);
Aktualisieren von Datensätzen
const updateData = { id: "00001", name: "John Smith", email: "john@example.com" };
const request = objectStore.put(updateData);
Löschen von Datensätzen
const request = objectStore.delete("00001");
request.onsuccess = (event) => {
console.log("Record deleted");
};
Arbeiten mit Cursorn
Cursor-Funktionalität verstehen
Cursor ermöglichen es Ihnen, Datensätze in einem Objektspeicher oder Index effizient zu durchlaufen und bieten eine Möglichkeit, Daten zu durchlaufen und zu manipulieren.
Navigieren durch Datensätze
const request = objectStore.openCursor();
request.onsuccess = (event) => {
const cursor = event.target.result;
if (cursor) {
console.log("Key:", cursor.key, "Value:", cursor.value);
cursor.continue(); // Move to the next record
} else {
console.log("No more records");
}
};
Ändern von Daten mit Cursorn
const transaction = db.transaction(["customers"], "readwrite");
const objectStore = transaction.objectStore("customers");
const request = objectStore.openCursor();
request.onsuccess = (event) => {
const cursor = event.target.result;
if (cursor) {
if (cursor.value.status === "inactive") {
const updateData = cursor.value;
updateData.status = "active";
cursor.update(updateData);
}
cursor.continue();
}
};
Schemamanagement und -Upgrades
Aktualisieren des Datenbankschemas
Wenn sich Ihre Anwendung weiterentwickelt, müssen Sie möglicherweise Ihr Datenbankschema ändern:
const request = indexedDB.open("MyDatabase", 2); // Increase version number
request.onupgradeneeded = (event) => {
const db = event.target.result;
// Check if the object store exists
if (!db.objectStoreNames.contains("newStore")) {
db.createObjectStore("newStore", { keyPath: "id" });
}
};
Migrieren von Daten während Upgrades
request.onupgradeneeded = (event) => {
const db = event.target.result;
const oldVersion = event.oldVersion;
if (oldVersion < 1) {
// First version setup
}
if (oldVersion < 2) {
// Migrate data to new schema
const transaction = event.target.transaction;
const oldStore = transaction.objectStore("oldStore");
const newStore = db.createObjectStore("newStore", { keyPath: "id" });
oldStore.openCursor().onsuccess = (event) => {
const cursor = event.target.result;
if (cursor) {
newStore.add(cursor.value);
cursor.continue();
}
};
}
};
Leistungsoptimierung
Effiziente Massenoperationen
Verwenden Sie für eine bessere Leistung Massenoperationen, wenn Sie mit mehreren Datensätzen arbeiten:
const transaction = db.transaction(["customers"], "readwrite");
const store = transaction.objectStore("customers");
// Add multiple records in a single transaction
customerList.forEach(customer => {
store.add(customer);
});
Verwenden von Indizes für schnellere Abfragen
Erstellen Sie Indizes für häufig abgefragte Eigenschaften, um einen schnelleren Datenabruf zu gewährleisten:
objectStore.createIndex("email", "email", { unique: true });
objectStore.createIndex("lastLogin", "lastLogin", { unique: false });
Best Practices für das Verbindungsmanagement
Öffnen Sie Verbindungen nur bei Bedarf und schließen Sie sie, wenn Sie fertig sind:
let db;
function openDB() {
const request = indexedDB.open("MyDatabase", 1);
request.onsuccess = (event) => {
db = event.target.result;
};
return request;
}
// When you're done with the database
function closeDB() {
if (db) {
db.close();
db = null;
}
}
Praxisbeispiel: Task-Manager mit Offline-Unterstützung
Datenbank-Setup
const request = indexedDB.open("TaskManagerDB", 1);
request.onupgradeneeded = (event) => {
const db = event.target.result;
const taskStore = db.createObjectStore("tasks", { keyPath: "id", autoIncrement: true });
// Create indexes for querying
taskStore.createIndex("status", "status", { unique: false });
taskStore.createIndex("dueDate", "dueDate", { unique: false });
};
Hinzufügen von Aufgaben
function addTask(taskData) {
const transaction = db.transaction(["tasks"], "readwrite");
const taskStore = transaction.objectStore("tasks");
return new Promise((resolve, reject) => {
const request = taskStore.add({
title: taskData.title,
description: taskData.description,
status: "pending",
dueDate: taskData.dueDate,
createdAt: new Date()
});
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
Abrufen und Anzeigen von Aufgaben
function getAllTasks() {
const transaction = db.transaction(["tasks"], "readonly");
const taskStore = transaction.objectStore("tasks");
return new Promise((resolve, reject) => {
const request = taskStore.openCursor();
const tasks = [];
request.onsuccess = (event) => {
const cursor = event.target.result;
if (cursor) {
tasks.push(cursor.value);
cursor.continue();
} else {
resolve(tasks);
}
};
request.onerror = () => reject(request.error);
});
}
Aktualisieren und Löschen von Aufgaben
function updateTaskStatus(id, newStatus) {
const transaction = db.transaction(["tasks"], "readwrite");
const taskStore = transaction.objectStore("tasks");
return new Promise((resolve, reject) => {
const getRequest = taskStore.get(id);
getRequest.onsuccess = () => {
const task = getRequest.result;
task.status = newStatus;
task.updatedAt = new Date();
const updateRequest = taskStore.put(task);
updateRequest.onsuccess = () => resolve(true);
updateRequest.onerror = () => reject(updateRequest.error);
};
getRequest.onerror = () => reject(getRequest.error);
});
}
Synchronisieren mit dem Server
function syncWithServer() {
if (!navigator.onLine) {
return Promise.reject(new Error("No internet connection"));
}
return getAllTasks()
.then(tasks => {
// Filter tasks that need syncing
const unsynced = tasks.filter(task => !task.synced);
// Send to server using fetch API
return fetch('https://api.example.com/tasks/sync', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(unsynced)
});
})
.then(response => response.json())
.then(result => {
// Mark tasks as synced
const transaction = db.transaction(["tasks"], "readwrite");
const taskStore = transaction.objectStore("tasks");
result.syncedIds.forEach(id => {
const request = taskStore.get(id);
request.onsuccess = () => {
const task = request.result;
task.synced = true;
taskStore.put(task);
};
});
return result;
});
}
// Listen for online events to sync automatically
window.addEventListener('online', syncWithServer);
Integrieren von Apidog für API-Management mit IndexedDB
Beim Erstellen von Anwendungen mit IndexedDB für die clientseitige Speicherung müssen Sie häufig mit Back-End-APIs interagieren, um Daten zu synchronisieren. Apidog bietet eine nahtlose Lösung für die Verwaltung dieser API-Interaktionen.

Warum Apidog die IndexedDB-Entwicklung verbessert
Bei der Entwicklung von Offline-fähigen Anwendungen mit IndexedDB bietet Apidog mehrere Vorteile:
Echtzeit-Synchronisierung: Apidog stellt sicher, dass Ihre API-Endpunkte, die für die Datensynchronisierung verwendet werden, immer ordnungsgemäß konfiguriert und getestet sind, wodurch Integrationsprobleme vermieden werden, wenn Ihre App online geht.
Mock-API-Antworten: Bei der Entwicklung von Offline-Funktionen ermöglichen Ihnen die intelligenten Mock-Engines von Apidog, API-Antworten zu simulieren, um Ihre IndexedDB-Synchronisierungslogik ohne einen Live-Server zu testen.

Kollaboratives API-Design: Wenn Ihr Team gleichzeitig an der Front-End-Speicherung und den Back-End-APIs arbeitet, erleichtert Apidog die Echtzeit-Zusammenarbeit an API-Spezifikationen.

Durch die Integration von Apidog in Ihren Entwicklungsworkflow schaffen Sie eine nahtlose Brücke zwischen clientseitiger Speicherung und serverseitiger Verarbeitung, wodurch Ihre Anwendung robuster und einfacher zu warten ist.