Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 48x 171x 171x 5x 166x 171x 171x 164x 1x 171x 171x 165x 171x | // navigator.locks when available; else an in-realm promise-chain mutex per
// name (jsdom + older browsers). The cross-tab guarantee comes from
// navigator.locks in real browsers; the fallback preserves in-realm
// exclusivity only — which is exactly the pre-Web-Locks status quo.
type LockCallback = (lock: { name: string }) => Promise<unknown>;
interface LockManagerLike {
request(name: string, callback: LockCallback): Promise<unknown>;
}
const chains = new Map<string, Promise<void>>();
export function withWebLock<T>(name: string, fn: () => Promise<T>): Promise<T> {
const locks = (
globalThis.navigator as (Navigator & { locks?: LockManagerLike }) | undefined
)?.locks;
if (locks?.request) {
return locks.request(name, () => fn()) as Promise<T>;
}
const prev = chains.get(name) ?? Promise.resolve();
const run = prev.then(fn);
// The chain must survive a rejected holder (swallow), and clean itself up
// once no later waiter has been appended.
const settled = run.then(
() => undefined,
() => undefined,
);
chains.set(name, settled);
void settled.then(() => {
if (chains.get(name) === settled) chains.delete(name);
});
return run;
}
|