Parallel and Async Are Not the Same Thing
Why JavaScript's async model has nothing to do with parallelism, what actually runs on a single thread, and what Web Workers really give you.
Here's the actual idea this post teaches, in one sentence: parallel means two things happening at the exact same instant, async on a single thread means one thing happening at a time in some order, and JavaScript is always the second one, no matter how fast or overlapping it looks.
Every pattern in this series solves a different complaint, but they all sit on top of that one fact. I used to use "parallel" and "async" as if they were the same word with two spellings.
They're not, and mixing them up makes async code far more confusing than it needs to be.
Same Instant vs. One at a Time
Picture a coffee shop with four espresso machines and four baristas. All four can pull a shot at the exact same instant, one customer's order finishing at the same moment as three other customers' orders. That's parallelism: more than one thing physically happening at the same instant.
Now picture the same shop with one barista and one machine. She still serves four customers, but never at the same instant. She finishes one drink, starts the next, finishes that, starts the next. One thing at a time, in some order, is not parallelism, even if all four drinks get made quickly.
The four machines above happen at the same instant. The one-barista row below happens one order after another. JavaScript is always the second row, no matter how fast it looks.
Parallelism Is a Hardware Thing
In computing, parallelism comes from threads running on separate CPU cores. One core can be executing an instruction at the exact same moment a different core executes a completely different instruction.
That's the real thing, actually happening together, not just looking like it.
Real machines don't have unlimited cores, but modern operating systems still juggle tens of thousands of tasks. The trick is a scheduling layer that hands out short slices of core time to far more tasks than there are cores, switching between them so fast it looks like everything runs together.
None of that scheduling is something your code controls or even sees. You write code assuming two things are "on separate threads," and the operating system decides how to actually spread them across the hardware you happen to have.
Parallelism exists for one reason: speed. If two chunks of work don't depend on each other, running them at the same instant instead of one after another gets the whole job done faster.
JavaScript Never Gets That
Your JavaScript, the actual .js file running in a browser tab or a Node process, executes on exactly one thread. At any given instant, there is exactly one line of your program running, full stop.
That's true even though the browser hosting it might use dozens of other threads for its own background work, work you never write or see. None of that is your code running in parallel with itself. Your code only ever gets one thread.
This single-thread guarantee is a genuine gift, not a limitation. A language where two threads can touch the same piece of memory at the same instant needs a whole toolkit for coordinating that access safely.
Two threads writing to the same variable at once can produce a different result depending on which one wins. JavaScript never has that race, because there's never a second thread trying to touch anything at the same instant in the first place.
That's the same trade this blog keeps coming back to in the functional-JavaScript series: fewer things that can touch a piece of state means less you have to hold in your head to trust it.
Web Workers: A Second Engine, Not a Second Thread for Your Code
There is one way to get real, separate-thread execution in the browser: a Web Worker. It spins up an entirely new instance of the JavaScript engine on its own thread.
That new instance is a stranger to your main code, not a helper thread inside it. It can't see your variables, can't call your functions, and doesn't share any memory with the script that created it. As far as either script is concerned, they might as well be two unrelated programs that happen to be running on the same machine.
The only way they talk is by sending messages back and forth, each one landing on the other side as an ordinary asynchronous event. A worker doesn't turn your program into multithreaded code. It gives you a second single-threaded program, with a mailbox connecting the two.
Every pattern the rest of this series covers, callbacks, promises, generators, all of it, describes a different way of managing that one single thread. None of them make JavaScript parallel.
They just get better at making one thread juggle a lot of waiting, without ever running two things at the exact same instant.
That raises the real question this series is actually about: if only one thing can ever run at a time, how does a program manage dozens of pending operations without falling apart? That's concurrency, and it's next.
Keep reading