Head of Product at Temporal. Previously lead architect and low-level systems programmer for scale out SaaS offering. Game engine developer, ML engineering expert. DMs open on Twitter.
JS is single threaded, but not single-file (as in lines at school). Even though it isn't parallel, it's still concurrent. Sending an HTTP request may take seconds or even minutes, if JS stopped executing code until a response came back from the request, the language would be unusable.
Your article writes that map is a construct that JS provides us that runs tasks in parallel.
But map doesn't care if you're passing it an async function or not—it runs a function on everything you pass it, in order. Notably, even this is possible, because async functions don't yield unless you actually call await:
Head of Product at Temporal. Previously lead architect and low-level systems programmer for scale out SaaS offering. Game engine developer, ML engineering expert. DMs open on Twitter.
At some level you're right that map isn't an inherently parallel construct. But I still stand by what I said, map has the potential of being parallelized on a level that a traditional for-loop does not. A for-loop explicitly surfaces a mechanism to enforce ordering, a map (and forEach) do not.
In your example, the code is not guaranteed to have a consistent result. The only way it could be consistent is if V8 guaranteed in-order execution of asynchronous tasks, which it does not.
Another differentiator in my mind is state. Anyone who has worked with distributed systems, knows that shared state is incredibly expensive. A traditional for-loop inherently provides shared state, the iterator/bounds check variable i. This inherently orders the loop, while map may be implemented as ordered, it's an implementation detail. Original MapReduce wasn't ordered.
Head of Product at Temporal. Previously lead architect and low-level systems programmer for scale out SaaS offering. Game engine developer, ML engineering expert. DMs open on Twitter.
That’s not true. If I await a web request in some random function, it will still be asynchronous as long as the random function is invoked asynchronously.
From the article:
I think you might have missed a couple paragraphs. In case this doesn't make sense, read my article about async, concurrency and parallelism.
Your article writes that
map
is a construct that JS provides us that runs tasks in parallel.But map doesn't care if you're passing it an async function or not—it runs a function on everything you pass it, in order. Notably, even this is possible, because async functions don't yield unless you actually call
await
:At some level you're right that
map
isn't an inherently parallel construct. But I still stand by what I said,map
has the potential of being parallelized on a level that a traditionalfor-loop
does not. Afor-loop
explicitly surfaces a mechanism to enforce ordering, amap
(andforEach
) do not.In your example, the code is not guaranteed to have a consistent result. The only way it could be consistent is if V8 guaranteed in-order execution of asynchronous tasks, which it does not.
Another differentiator in my mind is state. Anyone who has worked with distributed systems, knows that shared state is incredibly expensive. A traditional
for-loop
inherently provides shared state, the iterator/bounds check variable i. This inherently orders the loop, while map may be implemented as ordered, it's an implementation detail. Original MapReduce wasn't ordered.I would say the moment you slap
await
in there, the code is no longer asynchronous. It's blocking as any other line.That’s not true. If I await a web request in some random function, it will still be asynchronous as long as the random function is invoked asynchronously.
Try doing two awaits in a row and check if they run concurrently. This is the definition of synchronous.