4 ms·
Weird API to release the lock. What if you want to hold on to it? Then you need to do some silly promise wrapper. Would be better if there was a matching releas
by tantalor 2y ago
Weird API to release the lock. What if you want to hold on to it? Then you need to do some silly promise wrapper. Would be better if there was a matching release() function.
- rockwotj 2y agoProbably because there is no RAII semantics in JS and they don’t want to allow forgetting releasing the lock. Although the promise workaround is explicitly opting into this behavior
- slimsag 2y agoJavascript in browsers already has a full atomics API: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe... I'm not sure why Web Locks is useful TBH. I guess if you don't understand atomics it's a friendlier API?
- whilenot-dev 2y agoYou mean Atomics + SharedArrayBuffer, otherwise it won't be shared across agents. I can imagine all the postMessage calls and message handlers swirling around in all agents to approximate something like the Web Locks API for a simple lock, but tbh I'd take the Web Locks API any day.
- pavlov 2y agoThe Web Locks documentation explains that it works across tabs, i.e. separate processes: ”[…] allows a web app running in multiple tabs or workers to coordinate work and the use of resources” A locking API is much more natural and less error-prone for this use case than using shared memory and atomics.
- mrkeen 2y agoIt's "atomic" in the sense that it does one thing. It lets you do "actions", not "transactions". A transaction would allow you to do multiple things. If the atomics API gave you ability to do multiple things, you wouldn't need compareExchange, because you could just do compare and then exchange.
- jauntywundrkind 2y agoThe ergonomics here for 99.999% of uses seem great to me. Whatever async function you have can run for as long as it needs. That's using the language, not adding more userland craft. It's a good move.
- maxmcd 2y agoclass Lock { #release: () => void | undefined; constructor(public name: string) {} acquire() { if (this.#release !== undefined) throw new Error("Already locked"); navigator.locks.request(this.name, async (lock) => { await new Promise<void>(resolve => { this.#release = resolve; }); }); } release() { if (this.#release === undefined) throw new Error("Not locked"); this.#release(); } }
- whilenot-dev 2y agoYou're not treating the aquire phase correctly: class Lock { #resolve: (() => void) | undefined; #releasePromise: Promise<void> | undefined; constructor(public name: string) {} acquire(): Promise<void> { if (this.#releasePromise !== undefined) { throw new Error("Already aquired"); } return new Promise((resolveAquire, _rejectAquire) => { this.#releasePromise = new Promise((resolveRelease, _rejectRelease) => { navigator.locks.request(this.name, async (lock) => { await new Promise<void>((resolve, _reject) => { this.#resolve = resolve; resolveAquire(); }); resolveRelease(); }); }); }); } async release(): Promise<void> { if (this.#releasePromise === undefined) { throw new Error("Already released"); } this.#resolve(); await this.#releasePromise; this.#resolve = undefined; this.#releasePromise = undefined; } } ...the release phase still feels off without a Promise, but maybe somebody else can tackle that :D EDIT: think I fixed it, untested though
- wruza 2y agop = Promise.withResolvers() navigator.locks.request( "foo", p.promise, ) p.resolve() I guess there’s room for .requestWithResolvers() still, they rarely learn the first lesson. Even the $subj article seems to be unaware of it and uses the silly wrapper way.