Start · Sprachen · JavaScript · Referenz · WorkerGlobalScope.indexedDB

WorkerGlobalScope.indexedDB

Eigenschaft

Schreibgeschützte Eigenschaft, die in Web Workern eine <code>IDBFactory</code> liefert, um asynchron auf IndexedDB-Datenbanken zuzugreifen.

seit JavaScript Baseline: alle modernen Browser (seit ca. 2015) Kategorie: webapi

Signatur

WorkerGlobalScope.indexedDB

Beschreibung

Die schreibgeschützte Eigenschaft indexedDB der Schnittstelle WorkerGlobalScope liefert ein IDBFactory-Objekt. Damit können Dedicated Worker, Shared Worker und Service Worker IndexedDB-Datenbanken öffnen, anlegen und löschen, und zwar genauso wie im Hauptthread über window.indexedDB.

Im Worker-Kontext ist indexedDB global verfügbar. Man kann also direkt indexedDB.open() oder self.indexedDB.open() schreiben. Das eignet sich gut, um große Datenmengen außerhalb des Hauptthreads zu speichern oder zu verarbeiten, zum Beispiel beim Importieren großer JSON-Dateien, beim Zwischenspeichern von API-Antworten oder für Offline-Daten in einem Service Worker. Die Benutzeroberfläche bleibt dabei flüssig.

Worker und Hauptthread mit demselben Ursprung (Origin) greifen auf dieselben Datenbanken zu. Daten, die ein Worker schreibt, kann die Seite also direkt lesen. Die API arbeitet ereignisbasiert mit IDBRequest und den Ereignissen success, error und upgradeneeded. In der Praxis verpackt man sie deshalb meist in Promises.

Rückgabewert

Typ
IDBFactory
Beschreibung
Ein IDBFactory-Objekt mit den Methoden open(), deleteDatabase(), databases() und cmp().

Beispiele

Datenbank im Worker öffnen und Object Store anlegen

// worker.js
const request = indexedDB.open('app-cache', 1);

request.onupgradeneeded = (event) => {
  const db = event.target.result;
  if (!db.objectStoreNames.contains('artikel')) {
    db.createObjectStore('artikel', { keyPath: 'id' });
  }
};

request.onsuccess = () => {
  const db = request.result;
  console.log('Datenbank geöffnet:', db.name, 'Version', db.version);
  postMessage({ status: 'bereit' });
};

request.onerror = () => {
  console.error('Fehler beim Öffnen:', request.error);
};
Datenbank geöffnet: app-cache Version 1

Große Datenmengen im Worker per Promise-Wrapper speichern

// worker.js
const openDb = () => new Promise((resolve, reject) => {
  const req = self.indexedDB.open('app-cache', 1);
  req.onupgradeneeded = () => req.result.createObjectStore('artikel', { keyPath: 'id' });
  req.onsuccess = () => resolve(req.result);
  req.onerror = () => reject(req.error);
});

self.onmessage = async ({ data }) => {
  const response = await fetch(data.url);
  const artikel = await response.json();
  const db = await openDb();

  const tx = db.transaction('artikel', 'readwrite');
  const store = tx.objectStore('artikel');
  artikel.forEach((a) => store.put(a));

  tx.oncomplete = () => postMessage({ gespeichert: artikel.length });
  tx.onerror = () => postMessage({ fehler: tx.error?.message });
};

// main.js
// const worker = new Worker('worker.js');
// worker.onmessage = (e) => console.log(e.data);
// worker.postMessage({ url: '/api/artikel' });
{ gespeichert: 250 }

Service Worker: Offline-Daten aus IndexedDB ausliefern

// sw.js
const getAll = (storeName) => new Promise((resolve, reject) => {
  const req = indexedDB.open('app-cache', 1);
  req.onsuccess = () => {
    const tx = req.result.transaction(storeName, 'readonly');
    const getReq = tx.objectStore(storeName).getAll();
    getReq.onsuccess = () => resolve(getReq.result);
    getReq.onerror = () => reject(getReq.error);
  };
  req.onerror = () => reject(req.error);
});

self.addEventListener('fetch', (event) => {
  const url = new URL(event.request.url);
  if (url.pathname === '/api/artikel') {
    event.respondWith(
      fetch(event.request).catch(async () => {
        const daten = await getAll('artikel');
        return new Response(JSON.stringify(daten), {
          headers: { 'Content-Type': 'application/json' }
        });
      })
    );
  }
});

Vorhandene Datenbanken auflisten

// worker.js
const listen = async () => {
  if ('databases' in indexedDB) {
    const dbs = await indexedDB.databases();
    dbs.forEach(({ name, version }) => console.log(`${name} (v${version})`));
  } else {
    console.log('indexedDB.databases() wird nicht unterstützt');
  }
};
listen();
app-cache (v1)

// Wichtig · Fallstricke

  • Kein synchroner Zugriff: Die früher geplante synchrone IndexedDB-API für Worker wurde nie umgesetzt. Auch im Worker ist alles asynchron.
  • Kein localStorage in Workern: In Workern gibt es kein localStorage und kein sessionStorage. IndexedDB (oder die Cache API bzw. OPFS) ist dort der Weg, Daten dauerhaft zu speichern.
  • Transaktionen schließen sich automatisch: Eine Transaktion wird beendet, sobald keine Anfragen mehr ausstehen. Wer zwischen zwei Operationen await fetch() aufruft, bekommt einen TransactionInactiveError. Daher erst alle Daten laden und danach die Transaktion öffnen.
  • Versionskonflikte: Öffnen Seite und Worker dieselbe Datenbank mit unterschiedlichen Versionen, blockiert das Upgrade (Ereignis blocked). Deshalb auf versionchange reagieren und die Verbindung mit db.close() schließen.
  • Privater Modus und Speicherkontingente: In manchen Browsern ist IndexedDB im privaten Modus eingeschränkt oder wird beim Schließen gelöscht. Wenn das Kontingent überschritten ist, tritt ein QuotaExceededError auf.
  • Ursprung: Worker aus blob:- oder data:-URLs können einen undurchsichtigen Ursprung haben. Dann löst der Zugriff einen SecurityError aus.
  • Kompatibilität: Wird in allen modernen Browsern unterstützt. indexedDB.databases() ist in Firefox erst seit Version 126 verfügbar, deshalb vorher per Feature-Erkennung prüfen.