Signatur
Beschreibung
Jede Operation in IndexedDB läuft asynchron ab. Methoden wie IDBObjectStore.get(), put(), add(), delete(), openCursor() oder IDBIndex.getAll() geben kein Ergebnis direkt zurück, sondern ein IDBRequest-Objekt. Über dieses Objekt erfährt man, wann die Operation fertig ist und ob sie geklappt hat. Den Ausgang meldet der Browser über die Events success und error.
Wichtige Eigenschaften:
result: Ergebnis der Anfrage, z. B. der gelesene Datensatz, der Schlüssel oder ein Cursor. Solange die Anfrage läuft, führt ein Zugriff zu einerInvalidStateError-DOMException.error: EineDOMExceptionbei einem Fehlschlag, sonstnull.readyState:"pending"oder"done".source: Das Objekt, von dem die Anfrage ausging (IDBObjectStore,IDBIndex,IDBCursorodernull).transaction: DieIDBTransaction, zu der die Anfrage gehört (beim Öffnen einer Datenbank außerhalb vonupgradeneededist der Wertnull).onsuccess/onerror: Event-Handler-Eigenschaften, alternativ zuaddEventListener().
Der Untertyp IDBOpenDBRequest, den indexedDB.open() zurückgibt, erweitert IDBRequest um die Events upgradeneeded und blocked. In modernem Code verpackt man ein IDBRequest meist in ein Promise, damit sich async/await nutzen lässt.
Rückgabewert
IDBObjectStore.get() oder IDBIndex.openCursor() zurückgegeben.Beispiele
Datenbank öffnen und einen Datensatz lesen (onsuccess/onerror)
const openReq = indexedDB.open('shop', 1);
openReq.onupgradeneeded = () => {
const db = openReq.result;
const store = db.createObjectStore('produkte', { keyPath: 'id' });
store.add({ id: 1, name: 'Tastatur', preis: 49.9 });
};
openReq.onsuccess = () => {
const db = openReq.result;
const tx = db.transaction('produkte', 'readonly');
const request = tx.objectStore('produkte').get(1); // IDBRequest
console.log(request.readyState); // "pending"
request.onsuccess = () => {
console.log(request.readyState, request.result);
};
request.onerror = () => {
console.error('Lesefehler:', request.error);
};
};
IDBRequest in ein Promise verpacken (async/await)
const promisify = (request) =>
new Promise((resolve, reject) => {
request.addEventListener('success', () => resolve(request.result));
request.addEventListener('error', () => reject(request.error));
});
const speichern = async () => {
const db = await promisify(indexedDB.open('shop', 1));
const store = db.transaction('produkte', 'readwrite').objectStore('produkte');
const key = await promisify(store.put({ id: 2, name: 'Maus', preis: 19.9 }));
console.log('Gespeichert unter Schlüssel', key);
const alle = await promisify(store.getAll());
console.log(alle.length, 'Produkte');
};
speichern().catch(console.error);
Cursor-Request: mehrfaches success-Event
const req = indexedDB.open('shop', 1);
req.onsuccess = () => {
const store = req.result.transaction('produkte').objectStore('produkte');
const cursorReq = store.openCursor();
// success feuert für JEDEN Datensatz erneut
cursorReq.onsuccess = () => {
const cursor = cursorReq.result;
if (cursor) {
console.log(cursor.key, cursor.value.name, cursorReq.source === store);
cursor.continue();
} else {
console.log('Fertig');
}
};
};
Fehler abfangen und Transaktionsabbruch verhindern
const req = indexedDB.open('shop', 1);
req.onsuccess = () => {
const tx = req.result.transaction('produkte', 'readwrite');
const addReq = tx.objectStore('produkte').add({ id: 1, name: 'Duplikat' });
addReq.onerror = (event) => {
console.warn(addReq.error.name); // ConstraintError
event.preventDefault(); // Transaktion NICHT abbrechen
event.stopPropagation(); // nicht zu tx/db weiterleiten
};
tx.oncomplete = () => console.log('Transaktion abgeschlossen');
};
// Wichtig · Fallstricke
resultzu früh gelesen: Liest manresultodererror, solangereadyStatenoch"pending"ist, wirft das eineInvalidStateError-DOMException. Greif erst imsuccess- bzw.error-Handler darauf zu.- Fehler bricht die Transaktion ab: Ein
error-Event steigt vom Request über dieIDBTransactionbis zurIDBDatabaseauf. Ohneevent.preventDefault()wird die ganze Transaktion zurückgerollt. - Transaktionen schließen sich selbst: Eine Transaktion wird beendet, sobald keine Anfragen mehr offen sind. Wer zwischen zwei Requests auf ein anderes
awaitwartet (z. B. auffetch()), bekommt danach einenTransactionInactiveError. Innerhalb einer Transaktion sollten daher nur IndexedDB-Requests abgewartet werden. - Erfolgreicher Request heißt nicht gespeichert: Ein
success-Event beiput()/add()garantiert noch nicht, dass die Daten dauerhaft geschrieben sind. Darauf ist erst beimcomplete-Event der Transaktion Verlass. - Cursor: Bei
openCursor()wird dasselbe Request-Objekt nach jedemcontinue()wiederverwendet, undsuccessfeuert mehrfach. - Kompatibilität: Wird von allen modernen Browsern, in Web Workern und in Service Workern unterstützt. Im privaten Modus älterer Safari- und Firefox-Versionen war IndexedDB eingeschränkt oder nicht verfügbar. Für eine Promise-API empfiehlt sich die kleine Bibliothek idb.