'use strict'; // Map of id => function that releases a lock. const held = new Map(); let next_lock_id = 1; function processMessage(e) { const target = this; function respond(data) { target.postMessage(Object.assign(data, {rqid: e.data.rqid})); } switch (e.data.op) { case 'request': { const controller = new AbortController(); navigator.locks.request( e.data.name, { mode: e.data.mode || 'exclusive', ifAvailable: e.data.ifAvailable || false, signal: e.data.abortImmediately ? controller.signal : undefined, }, lock => { if (lock === null) { respond({ack: 'request', failed: true}); return; } let lock_id = next_lock_id++; let release; const promise = new Promise(r => { release = r; }); held.set(lock_id, release); respond({ack: 'request', lock_id: lock_id}); return promise; }).catch(e => { respond({ack: 'request', error: e.name}); }); if (e.data.abortImmediately) { controller.abort(); } break; } case 'release': held.get(e.data.lock_id)(); held.delete(e.data.lock_id); respond({ack: 'release', lock_id: e.data.lock_id}); break; } } self.addEventListener('message', processMessage); self.addEventListener('connect', ev => { // Shared worker case ev.ports[0].onmessage = processMessage; });