Makes me wonder what part of the pattern you think is "too clever"? I think it is fairly easy to reason about when the lock is restricted to the encompassing block and automatically dropped when you leave the block.
It’s kind of a weird design that some of your variables (which you can define anywhere in the scope FWIW) just randomly define a critical section. I strongly prefer languages that do a
with lock {
// do stuff
}
design. This could be C++ too to be honest because lambdas exist but RAII is just too common for people to design their locks like this.
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.
'using' fixes having to do cleanup in a finally {} handler, which you can a) forget, and b) often messes up scoping of variables as you need to move them outside the 'try' block.
It also creates additional finalization semantics for a using-ed value. Which has all sorts of implications. lock.do(async (lock) => {work}) is a similar construct - a scope-limited aquisition that requires nothing special.
Catch/finally not sharing a scope with try is a repeated mistake, that I surely agree with!