Signatur
Beschreibung
advance() bewegt einen IDBCursor (bzw. IDBCursorWithValue) um eine feste Anzahl an Positionen in der Richtung, die beim Öffnen des Cursors festgelegt wurde ("next", "prev", "nextunique", "prevunique"). Anders als continue(), das immer genau einen Schritt oder bis zu einem bestimmten Schlüssel springt, überspringt advance(n) gezielt n − 1 Datensätze und landet auf dem n-ten folgenden Eintrag.
Typische Einsatzfälle sind Paginierung (Offset überspringen, dann eine Seite lesen), das Lesen jedes n-ten Eintrags (Stichproben, Ausdünnen von Messreihen) oder das Überspringen eines bekannten Präfixes. Der Aufruf ist asynchron: Er liefert nichts zurück, sondern löst erneut das success-Ereignis auf dem ursprünglichen IDBRequest aus. Dort steht in request.result der Cursor an seiner neuen Position – oder null, wenn das Ende des Bereichs überschritten wurde.
Wichtig: Pro success-Ereignis darf nur einmal advance() bzw. continue() aufgerufen werden. Außerdem muss die Transaktion noch aktiv sein – zwischen zwei Cursor-Schritten darf kein await auf fremde Promises (z. B. fetch) stehen, sonst wird die Transaktion automatisch beendet.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $count Pflicht | number | Anzahl der Positionen, um die der Cursor vorrücken soll. Muss eine ganze Zahl > 0 sein (unsigned long). advance(1) entspricht continue(). |
Beispiele
Paginierung: Offset überspringen und eine Seite lesen
// Liefert Seite `page` (0-basiert) mit `pageSize` Einträgen aus dem Store "artikel"
const getPage = (db, page, pageSize) =>
new Promise((resolve, reject) => {
const tx = db.transaction('artikel', 'readonly');
const request = tx.objectStore('artikel').openCursor();
const items = [];
let skipped = page === 0;
request.onsuccess = () => {
const cursor = request.result;
if (!cursor) return resolve(items); // Ende erreicht
if (!skipped) {
skipped = true;
cursor.advance(page * pageSize); // Offset in einem Schritt überspringen
return;
}
items.push(cursor.value);
if (items.length < pageSize) cursor.continue();
else resolve(items);
};
request.onerror = () => reject(request.error);
});
// Nutzung
const openReq = indexedDB.open('shop', 1);
openReq.onupgradeneeded = () => {
const store = openReq.result.createObjectStore('artikel', { keyPath: 'id' });
for (let id = 1; id <= 25; id++) store.add({ id, name: `Artikel ${id}` });
};
openReq.onsuccess = async () => {
const seite = await getPage(openReq.result, 2, 10);
console.log(seite.map((a) => a.id));
};
Jeden dritten Messwert lesen (Ausdünnen)
const sampleEvery = (db, step) =>
new Promise((resolve, reject) => {
const request = db
.transaction('messwerte')
.objectStore('messwerte')
.openCursor();
const samples = [];
request.onsuccess = () => {
const cursor = request.result;
if (cursor) {
samples.push(cursor.key);
cursor.advance(step); // n-1 Einträge überspringen
} else {
resolve(samples);
}
};
request.onerror = () => reject(request.error);
});
// Bei Schlüsseln 1..10:
// sampleEvery(db, 3).then(console.log);
Rückwärts laufen mit Richtung "prev"
// Die neuesten Einträge zuerst, dabei die ersten 5 überspringen
const request = db
.transaction('logs')
.objectStore('logs')
.openCursor(null, 'prev');
let first = true;
request.onsuccess = () => {
const cursor = request.result;
if (!cursor) return;
if (first) {
first = false;
cursor.advance(5); // bewegt sich in Laufrichtung, also rückwärts
return;
}
console.log('Log-Eintrag:', cursor.key);
cursor.continue();
};
// Wichtig · Fallstricke
TypeErrorbeicount= 0 oder negativem Wert. Werte, die sich nicht in eine gültige ganze Zahl umwandeln lassen, führen ebenfalls zu einem Fehler.InvalidStateError, wenn der Cursor bereits weiterbewegt wird (zweiter Aufruf vonadvance()/continue()im selbensuccess-Handler) oder wenn er schon hinter dem Ende steht bzw. seine Quelle gelöscht wurde.TransactionInactiveError, wenn die Transaktion nicht mehr aktiv ist – z. B. weil zwischen den Schritten auf einenfetch()odersetTimeoutgewartet wurde.- Die Lese-Richtung bestimmt die Bewegung: Bei
"prev"gehtadvance()rückwärts. Bei"nextunique"/"prevunique"werden doppelte Index-Schlüssel nicht mitgezählt. - Performance: Der Browser muss für den Offset trotzdem durch den Index laufen. Für tiefe Paginierung ist es meist schneller, sich den letzten Schlüssel zu merken und mit
IDBKeyRange.lowerBound(key, true)neu zu beginnen. Für einfache Massenabfragen sindgetAll()/getAllKeys()mitcountoft die bessere Wahl. - Kompatibilität: wird in allen modernen Browsern unterstützt, auch in Web Workern.