Signatur
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
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 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();
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));
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));
// Wichtig · Fallstricke
- Nur in sicheren Kontexten (HTTPS oder
localhost) verfügbar; sonst istnavigator.locksundefined. Vorab mit'locks' in navigatorprü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
signaleinen 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 einemNotSupportedError. - 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.