Start · Sprachen · JavaScript · Referenz · WorkerNavigator.locks

WorkerNavigator.locks

Eigenschaft

Gibt im Worker-Kontext das <code>LockManager</code>-Objekt der Web Locks API zurück, mit dem sich benannte Sperren anfordern und abfragen lassen.

seit JavaScript Baseline 2022: Chrome 69, Edge 79, Firefox 96, Saf Kategorie: webapi

Signatur

WorkerNavigator.locks

Beschreibung

Die schreibgeschützte Eigenschaft navigator.locks ist in Dedicated Workern, Shared Workern und Service Workern über WorkerNavigator verfügbar. Sie liefert einen LockManager, also dieselbe Schnittstelle, die im Hauptthread über Navigator.locks erreichbar ist. Über request() wird eine benannte Sperre angefordert, über query() lässt sich der aktuelle Zustand aller Sperren des Ursprungs abfragen.

Sperren gelten ursprungsweit: Ein Worker, mehrere Tabs und ein Service Worker desselben Ursprungs teilen sich denselben Satz an Sperrnamen. Deshalb eignet sich die API gut, um Zugriffe auf gemeinsame Ressourcen wie IndexedDB, OPFS-Dateien oder Netzwerk-Synchronisation über Thread- und Tab-Grenzen hinweg zu koordinieren, zum Beispiel damit nur ein Worker gleichzeitig eine Synchronisation mit dem Server ausführt.

Eine Sperre bleibt so lange gehalten, bis das Promise, das der Callback von request() zurückgibt, erfüllt oder abgelehnt ist. Deshalb wird der Callback typischerweise als async-Funktion geschrieben. Es gibt exklusive Sperren (Standard) und gemeinsame Sperren (mode: "shared"), die sich nach dem Muster „mehrere Leser, ein Schreiber“ einsetzen lassen.

Rückgabewert

Typ
LockManager
Beschreibung
Das LockManager-Objekt des aktuellen Ursprungs, mit den Methoden request(name, [options], callback) und query(). Bei jedem Zugriff wird dasselbe Objekt zurückgegeben.

Beispiele

Exklusive Sperre im Worker für eine Synchronisation

// sync-worker.js
const syncWithServer = async () => {
  await navigator.locks.request('daten-sync', async (lock) => {
    console.log(`Sperre erhalten: ${lock.name} (${lock.mode})`);
    const res = await fetch('/api/sync', { method: 'POST' });
    console.log('Sync-Status:', res.status);
  }); // Sperre wird hier freigegeben
  console.log('Sperre freigegeben');
};

self.addEventListener('message', (e) => {
  if (e.data === 'sync') syncWithServer();
});
Sperre erhalten: daten-sync (exclusive) Sync-Status: 200 Sperre freigegeben

Sperre nur bei Verfügbarkeit (ifAvailable)

const tryCleanup = async () => {
  const done = await navigator.locks.request(
    'cache-cleanup',
    { ifAvailable: true },
    async (lock) => {
      if (!lock) {
        console.log('Ein anderer Kontext räumt bereits auf – übersprungen.');
        return false;
      }
      const cache = await caches.open('v1');
      const keys = await cache.keys();
      await Promise.all(keys.map((req) => cache.delete(req)));
      return true;
    }
  );
  console.log('Aufgeräumt:', done);
};

tryCleanup();
Aufgeräumt: true

Gemeinsame Lesesperre mit Timeout per AbortSignal

const readConfig = async () => {
  try {
    return await navigator.locks.request(
      'config',
      { mode: 'shared', signal: AbortSignal.timeout(2000) },
      async () => {
        const res = await fetch('/config.json');
        return res.json();
      }
    );
  } catch (err) {
    if (err.name === 'TimeoutError' || err.name === 'AbortError') {
      console.warn('Sperre nicht rechtzeitig erhalten');
      return null;
    }
    throw err;
  }
};

readConfig().then((cfg) => console.log('Konfiguration:', cfg));
Konfiguration: { theme: 'dark' }

Aktuellen Sperrzustand abfragen

const state = await navigator.locks.query();
console.log('Gehalten:', state.held.map((l) => l.name));
console.log('Wartend:', state.pending.map((l) => l.name));
Gehalten: [ 'daten-sync' ] Wartend: [ 'daten-sync' ]

// Wichtig · Fallstricke

  • Nur in sicheren Kontexten (HTTPS oder localhost) verfügbar; sonst ist navigator.locks undefined. Vorab mit 'locks' in navigator prüfen.
  • Kompatibilität: seit März 2022 in allen aktuellen Browsern unterstützt (Chrome/Edge 69+, Firefox 96+, Safari 15.4+). Ältere Browser brauchen eine Ausweichlösung.
  • Deadlock-Gefahr: Wer innerhalb eines Callbacks dieselbe exklusive Sperre erneut anfordert oder zwei Sperren in wechselnder Reihenfolge anfordert, kann sich selbst blockieren. Sperren immer in fester Reihenfolge anfordern oder mit signal einen Timeout setzen.
  • Gibt der Callback kein Promise zurück (keine async-Funktion), wird die Sperre sofort nach dem synchronen Durchlauf freigegeben, auch wenn noch asynchrone Arbeit läuft.
  • Sperrnamen, die mit - beginnen, sind reserviert und führen zu einem NotSupportedError.
  • Wird ein Worker beendet (terminate()) oder ein Tab geschlossen, gibt der Browser alle gehaltenen Sperren automatisch frei.
  • Sperren sind pro Ursprung und pro Speicherpartition gültig. Kontexte hinter anderen Ursprüngen oder in partitionierten Drittanbieter-iframes teilen sie nicht.