Signatur
Beschreibung
IndexedDB arbeitet asynchron: Jede Lese- oder Schreiboperation wie get(), put(), add(), delete(), count() oder openCursor() gibt sofort ein IDBRequest-Objekt zurück. Ist die Operation abgeschlossen, feuert der Browser am Request entweder success oder error. Das success-Ereignis ist also der Moment, an dem das Ergebnis in request.result bereitsteht.
Du kannst den Handler per request.addEventListener("success", handler) oder über die Eigenschaft request.onsuccess = handler registrieren. Das Ereignis ist ein einfaches Event (kein spezielles Unterobjekt), es bubbelt nicht und ist nicht abbrechbar. event.target verweist auf den Request, das Ergebnis liest du über event.target.result.
Bei Cursorn (openCursor(), openKeyCursor()) wird success mehrfach ausgelöst: einmal pro Datensatz nach jedem cursor.continue() und ein letztes Mal mit result === null, wenn keine weiteren Einträge mehr vorhanden sind. Auch IDBOpenDBRequest (von indexedDB.open()) erbt dieses Ereignis. Dort feuert es, nachdem ein eventuelles upgradeneeded abgeschlossen ist, und liefert die IDBDatabase.
Wichtig: success an einem einzelnen Request bedeutet nicht, dass die Daten dauerhaft gespeichert sind. Das ist erst sicher, wenn die zugehörige Transaktion das complete-Ereignis auslöst.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignisname, immer "success". |
|
| $handler Pflicht | (event: Event) => void | Callback, der das Event erhält. event.target ist der auslösende IDBRequest, das Ergebnis steht in event.target.result. |
|
| $options | boolean | AddEventListenerOptions | false | Übliche Optionen von addEventListener, z. B. { once: true }. |
Rückgabewert
addEventListener gibt nichts zurück. Das eigentliche Ergebnis der Operation steht in request.result (z. B. ein Datensatz, ein Schlüssel, eine Anzahl, ein IDBCursorWithValue oder undefined).Beispiele
Datenbank öffnen und Datensatz lesen (addEventListener)
const openReq = indexedDB.open("shop", 1);
openReq.addEventListener("upgradeneeded", () => {
const db = openReq.result;
const store = db.createObjectStore("produkte", { keyPath: "id" });
store.put({ id: 1, name: "Tastatur", preis: 49.9 });
});
openReq.addEventListener("success", () => {
const db = openReq.result;
const tx = db.transaction("produkte", "readonly");
const getReq = tx.objectStore("produkte").get(1);
getReq.addEventListener("success", (event) => {
console.log("Gefunden:", event.target.result);
});
});
Über die onsuccess-Eigenschaft Einträge zählen
const openReq = indexedDB.open("shop", 1);
openReq.onsuccess = () => {
const db = openReq.result;
const countReq = db
.transaction("produkte")
.objectStore("produkte")
.count();
countReq.onsuccess = () => {
console.log(`Anzahl Produkte: ${countReq.result}`);
};
countReq.onerror = () => console.error(countReq.error);
};
Cursor: success feuert pro Datensatz
const openReq = indexedDB.open("shop", 1);
openReq.onsuccess = () => {
const db = openReq.result;
const cursorReq = db
.transaction("produkte")
.objectStore("produkte")
.openCursor();
cursorReq.onsuccess = () => {
const cursor = cursorReq.result;
if (cursor) {
console.log(cursor.key, cursor.value.name);
cursor.continue(); // löst das nächste success aus
} else {
console.log("Fertig");
}
};
};
Request als Promise verpacken für async/await
const promisify = (request) =>
new Promise((resolve, reject) => {
request.addEventListener("success", () => resolve(request.result), { once: true });
request.addEventListener("error", () => reject(request.error), { once: true });
});
const main = async () => {
const db = await promisify(indexedDB.open("shop", 1));
const store = db.transaction("produkte").objectStore("produkte");
const produkt = await promisify(store.get(1));
console.log(produkt?.name);
};
main();
// Wichtig · Fallstricke
- Ein Request bedeutet noch keine dauerhafte Speicherung: Bei Schreiboperationen solltest du auf
transaction.oncompletewarten, bevor du der Nutzerin oder dem Nutzer „gespeichert“ meldest. Die Transaktion kann nach einem erfolgreichen Request immer noch abgebrochen werden. - Transaktionen schließen sich automatisch: Nach dem
success-Handler bleibt die Transaktion nur aktiv, wenn du synchron neue Requests stellst. Einawaitauf etwas, das nicht aus IndexedDB kommt (z. B.fetch), führt danach zu einemTransactionInactiveError. - Ein leeres Ergebnis ist kein Fehler:
get()auf einen nicht vorhandenen Schlüssel löstsuccessmitresult === undefinedaus, nichterror. - Wenn du
resultliest, bevor der Request fertig ist (readyState !== "done"), wirft das einenInvalidStateError. - Bei
indexedDB.open()kann stattsuccessauchblockedauftreten, wenn andere Tabs die alte Version noch geöffnet haben. - Kompatibilität: Das Ereignis wird von allen modernen Browsern und in Web Workern unterstützt. In privaten Fenstern mancher Browser (ältere Firefox-Versionen) kann IndexedDB eingeschränkt sein.