I am in no way an expert in JavaScript nor in concurrent programming. But I spent about 2 days trying to make this work with Worker
, locally and in the online editor, and all attempts fail.
I can now strongly support the argument for async
tests for this exercise.
The problem is, that new Promise()
does not really do anything concurrently, until you do something that “forces” asynchronous behaviour. I’m elaborating this on @ErikSchierboom solution:
export const parallelLetterFrequency = (texts) => {
let frequencies = {};
Promise.all(texts.map((text) => letterFrequency(frequencies, text)));
return frequencies;
};
const letterFrequency = (frequencies, text) => {
return new Promise((resolve) => {
for (const [letter] of text.toLowerCase().match(/\p{Letter}/gu) || [])
frequencies[letter] = (frequencies[letter] || 0) + 1;
resolve(frequencies);
});
};
This works perfectly well, because it does not do anything asynchronously. It looks like it does, but it doesn’t. It immediately fails (always returns {}
), when “forcing” the Promise
to go async:
const letterFrequency = (frequencies, text) => {
return new Promise((resolve) => {
setTimeout(() => {
for (const [letter] of text.toLowerCase().match(/\p{Letter}/gu) || [])
frequencies[letter] = (frequencies[letter] || 0) + 1;
resolve(frequencies);
}, 100);
});
};
In theory, this should yield exactly the same result as before. But it doesn’t. The real async’ed timeout callback does return the correct result, but the main thread returns {}
for all inputs before the Promises are resolved. Promise.allSettled()
doesn’t change that.
When waiting for all Promises being resolved using .then()
, the variable is indeed filled in correctly. But you cannot wait to return it after .then()
is done:
export const parallelLetterFrequency = (texts) => {
let frequencies = {};
Promise.all(texts.map((text) => letterFrequency(frequencies, text)))
.then(() => console.log(frequencies));
return frequencies;
};
There is no way to get to the correct result reliably from that function, because nothing can wait for the Promise to be resolved, but .then()
. And this makes it impossible to do an async solution or one using Worker
without real async testing.