I would say that by using setInterval you are buying into this kind of behavior and would have to create your own synchronization.
If you are saying that this transpilation step changes the semantics of the code, then I completely agree!
I would say that by using setInterval you are buying into this kind of behavior and would have to create your own synchronization.
If you are saying that this transpilation step changes the semantics of the code, then I completely agree!
const backends = {}
async function setupBackend(host) { /* boot server */ }
function getBackend(host) {
if (!backends[host]) {
backends[host] = setupBackend(host)
}
return backends[host]
}
That if block is effectively a critical section: it relies on explicitly not awaiting the result of setupBackend(), so that the promise will be stored into backends[host] (to be reused by subsequent calls to getBackend()) before anything else can happen. Injecting `async` will break this behavior, causing the backend to be booted multiple times.[1] https://github.com/wolfgang42/webd/blob/8cf28447468dd4745262...
const backends = {}
async function setupBackend(host) { /* boot server */ }
function getBackend(host) {
if (!backends[host]) {
backends[host] = 'FLAG' // or something
setupBackend(host)
.then(backend => backends[host] = backend)
} else if (backends[host] === 'FLAG') {
// no-op
} else {
return backends[host]
}
}I tried writing some code for this comment that used an explicitly constructed Promise as the intermediate value with some logic to resolve it once setup was complete, but then I realized that it had exactly the same problem with that being implicitly waited on. Maybe there’s some clever way to work around this but it’s going to be a lot more complicated.
Of course, if you do insist on a JS dialect with implicit await, the easy fix for this problem (since you’re transpiling anyway) is to just introduce a `noawait` keyword that turns the await insertion off for a block, to explicitly mark it as atomic.
[ETA: also, in the general case there’s a race condition if someone calls the function again while it’s awaiting the initial flag value. That doesn’t happen with your code because the OP library happens to not await literals, but that’s kind of fragile: I can easily see a situation where someone tries to introduce e.g. a counter into the flag and causes a non-obvious race.]
let x = 0;
doSomethingAsync(); // does not touch x
console.log(x);
There's no guarantee that x will have the value 0 by the time you get to console.log(x). The value of x might have been changed by an outside function that just happened to run between your statements. In synchronous JS this would never happen as callbacks are scheduled to run only at the end of a function, and if they change x the change will only be applied after x is printed.
The change in behavior will break a lot of existing code, since the synchronous behavior of a function is a core feature and assumption of the language.
I completely see that this will break existing code, but I don't see how this is different from the behavior of Go (where the setTimeout code would be something in a different goroutine) or Python?
In the end this shows that JS is unequipped to handle such behavior without significant changes to the core language.
Then even in a synchronous context you'd have no guarantee that it wouldn't be modified:
function soSomethingSync() {
window.someObj.someProp = 12;
}
let x = window.someObj;
soSomethingSync();
console.log(x)
This has nothing whatsoever to do with sync vs async.It is one of the main reasons people like immutability/functional programming. But that's its own topic.
Its a fundamental concurrency pattern used in a lot of languages, often for UI threads and such. There's a lot of information on this topic and it certainly is about async/yielding.