// maybe its value is already being fetched
const future = futurecache[key];
if(future) {
return future;
}
It indeed fixes the problem in a JS lock-free way.
Note that, as wolfgang42 has shown in a sibling comment, the original cache map isn't necessary if you're using a future map, since the futures already contain the result:
async function fetchDataAndUpdateCache(key) {
// maybe its value is cached already
const cachedData = getFromCache(key);
if (cachedData) {
return cachedData;
}
// Simulate fetching data from an external source
const newDataFuture = mockFetch(`https://example.com/data/${key}`); // Placeholder fetch
updateCache(key, newDataFuture);
return newDataFuture;
}
---
But note that this kind of problem is much easier to fix than to actually diagnose.
My hypothesis is that the lax attutide of Node programmers towards concurrency is what causes subtle bugs like these to happen in the first place.
Python, for example, also has single-threaded async concurrency like Node, but unlike Node it also has all the standard synchronization primitives also implemented in asyncio: https://docs.python.org/3/library/asyncio-sync.html
Wolfgang's optimization is very nice, I also found interesting his signal of a non-async function that returns a promise as an "atomic". I don't particularly like typed JS, so it would be less visible to me.
Absolutely agree on the observability of such things. One area I think shows some promise, though the tooling lags a bit, is in async context[0] flow analysis.
One area I have actually used it so far is in tracking down code that is starving the event loop with too much sync work, but I think some visualization/diagnostics around this data would be awesome.
If we view Promises/Futures as just ends of a string of a continued computation, whos resumption is gated by some piece of information, the points between where you can weave these ends together is where the async context tracking happens and lets you follow a whole "thread" of state machines that make up the flow.
Thinking of it this way, I think, also makes it more obvious how data between these flows is partitioned in a way that it can be manipulated without locking.
As for the node dev's lax attitude, I would probably be more agressive and say it's an overall lack of formal knowledge on how computing and data flow works. As an SE in DevOps a lot of my job is to make software work for people that don't know how computers, let alone platforms, work.
ETA: I appreciate the time you took to make the example, also I changed the extension to `mjs` so the async IIFE isn't needed.