Not that it's super important, but Web Locks API is getting some circulation after a question about how you keep multiple pages from trying to use a (single-use only) oauth refresh token at the same time. Which is a pretty good use case for this feature! https://bsky.app/profile/ambarvm.bsky.social/post/3lakznzipt...
If you really wanted it to be at the top level you could probably turn it into an explicit `release` call using a wrapper and two `Promise` constructors, though that would probably be a bad idea since it could introduce bugs
Subjectiveness aside on what’s more readable… your proposing a new language feature would be more readable than an API design. To me, the MDN proposal is declarative whereas your proposal is imperative. And with my subjectiveness, JavaScript shines in declarative programming.
I wish the compatibility tables on MDN gave an indicator of when a feature became available.
My ideal would be a thing that says "this hit 90% of deployed browsers 4 years ago", but just seeing the date it was added to each of the significant browser families would be amazingly useful.
Using the Web Locks API page as an example, let's say we want to know when `LockManager` was added to Chrome. Here are the steps:
1. View the page: https://developer.mozilla.org/en-US/docs/Web/API/Web_Locks_A...
2. Scroll down to the Browser compatibility table
3. Find the cell you're interested in, in this example we're looking at where the `LockManager` row meets the Chrome column.
4. We see a check and a version number (in this case 69).
So at this point we know that it has existed since version 69.
Now in the case that we don't know that Chrome's current version is already < 100 and we need to know when a feature gained support:
5. Click on the cell to view the timeline of that cell.
Now we know that it was released on 2018-09-04, and it never had a smaller release requiring browser flags/prefixes/experiment flags/etc...
I think this is the idea behind the Baseline <Year> standard you see on a lot of mdn features now, it shows the year when the feature was available in all 3 major browser engines
Why only in secure contexts? You can use storage APIs in insecure contexts, doing this by spinning, but the lock API which seems much more innocuous requires a secure context?
I believe most new capabilities are limited to secure contexts, in part as a way of discouraging bad habits, even when there’s no particular risk. The ideal is that everything should run in a secure context, but it’s a hard sell removing existing functionality from insecure contexts. If it were being added now, I’m pretty sure storage APIs would be secure-only.
I'd presume that a MITM could set, release and read locks, by which it might determine that you have certain sites open.
In general¹, I presume that any API that uses "same origin" as bounding criteria, must be secure. Since there's no way to enforce this "same origin" in insecure contexts.
--
¹ Aside from the idea that maybe just make all new APIs "secure only", just to discourage insecure contexts.
Why would that matter? The tabs don't share memory. Any code doesn't run when it tries to acquire a lot that another piece of code from another tab has already acquired. The two tabs don't even need to run the same app.
Well, it might matter for functionality in the application.
After you fix a lock-related bug for example, how do you deal with an open tab running a different version of your code that is erroneously misusing a lock?
You need to account for that when you release new code, yeah? Rename the lock maybe? Some other logic?
I’ve been using this for a while now. But one thing I recently worked on required these locks to be extremely efficient. Does anyone have any benchmarks on usage of these locks? Preferably compared to the use of rust’s tokio mutex from a wasm context.
You should write your own benchmarks! I've been using mitata for microbenchmarks which is what the bun and deno people use for their cool benchmark charts. It's fast and tries to call the system GC between runs which helps reduce bias. github: https://github.com/evanwashere/mitata
I find iterating in mitata super fun and a little addictive. It's hard to write a representative micro-benchmark, but optimizing them is still useful as long as you aren't making anything worse, which is often easy to avoid. I recently used mitata-benchmark-guided optimization to rewrite a core data structure at Notion for a 5% latency decrease on a few endpoints at p90/95/99. One of our returning interns used it to assess serialization libraries and she found one 3x faster. a+++ would recommend
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.
The 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.
Probably 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
p = 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.
I guess I don't actually get the point, because if I am locking a resource in one tab so that other tabs can't use that resource... how is that not going to lead to behavior that a user would think was broken.
Two tabs try to refresh the token at the same time, user opened tab 2, tab 2 can't refresh because things locked in tab 1 - user thinks app is broken? Isn't that the way it would happen. I guess you can detect it is locked in another tab though so you could give the user a warning about this?
I guess I am missing something about the scenario..
Maybe it's old person yelling at cloud vibes, but I'm already annoyed enough at the majority of SPAs for breaking so many useful default browser features, such as stable links, navigation, multi-tab functionality, open in new tab etc. This is only gonna make them even more cancer my gut feeling tells me.
This would be so much more readable with `using`
(https://github.com/tc39/proposal-explicit-resource-managemen...)Edit: Nevermind, release of the lock is automatic when the callback resolves its promise. I get it now.
My ideal would be a thing that says "this hit 90% of deployed browsers 4 years ago", but just seeing the date it was added to each of the significant browser families would be amazingly useful.
Using the Web Locks API page as an example, let's say we want to know when `LockManager` was added to Chrome. Here are the steps:
1. View the page: https://developer.mozilla.org/en-US/docs/Web/API/Web_Locks_A... 2. Scroll down to the Browser compatibility table 3. Find the cell you're interested in, in this example we're looking at where the `LockManager` row meets the Chrome column. 4. We see a check and a version number (in this case 69).
So at this point we know that it has existed since version 69.
Now in the case that we don't know that Chrome's current version is already < 100 and we need to know when a feature gained support:
5. Click on the cell to view the timeline of that cell.
Now we know that it was released on 2018-09-04, and it never had a smaller release requiring browser flags/prefixes/experiment flags/etc...
Now I'm digging around in https://github.com/mdn/browser-compat-data/blob/main/api/Loc... and trying to find the browser release dates data...
Ooh, https://bcd.developer.mozilla.org/bcd/api/v0/current/api.Loc... is even better - it expands those browser dates and it's served with access-control-allow-origin: *
https://caniuse.com/mdn-api_lock
Search around and you’ll find various information and explanations about it. https://blog.mozilla.org/security/2018/01/15/secure-contexts... is one, though https://w3ctag.github.io/design-principles/#secure-context has apparently been significantly watered down from what it was originally—see the initial proposal in https://github.com/w3ctag/design-principles/pull/75, and what was then merged in https://github.com/w3ctag/design-principles/pull/89.
In general¹, I presume that any API that uses "same origin" as bounding criteria, must be secure. Since there's no way to enforce this "same origin" in insecure contexts.
--
¹ Aside from the idea that maybe just make all new APIs "secure only", just to discourage insecure contexts.
Or the same way two completely different processes can access the same address space with shared memory IPC.
You aren't running in the same memory space, you're just communicating with a shared resource.
After you fix a lock-related bug for example, how do you deal with an open tab running a different version of your code that is erroneously misusing a lock?
You need to account for that when you release new code, yeah? Rename the lock maybe? Some other logic?
I find iterating in mitata super fun and a little addictive. It's hard to write a representative micro-benchmark, but optimizing them is still useful as long as you aren't making anything worse, which is often easy to avoid. I recently used mitata-benchmark-guided optimization to rewrite a core data structure at Notion for a 5% latency decrease on a few endpoints at p90/95/99. One of our returning interns used it to assess serialization libraries and she found one 3x faster. a+++ would recommend
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?
EDIT: think I fixed it, untested though
- single page application using access and refresh tokens to interact with an API
- refresh is one time use, as recommended by the OAuth security best practices[1]
- SPA is open in more than one tab
- two tabs try to refresh the token at the same time, second one fails because refresh token is used up
0: https://bsky.app/profile/ambarvm.bsky.social/post/3lakznzipt...
1: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-secur...
Two tabs try to refresh the token at the same time, user opened tab 2, tab 2 can't refresh because things locked in tab 1 - user thinks app is broken? Isn't that the way it would happen. I guess you can detect it is locked in another tab though so you could give the user a warning about this?
I guess I am missing something about the scenario..