Why async/await Doesn’t Make JavaScript Code Parallel
Why async/await Doesn’t Make JavaScript Code Parallel
async/await often looks like parallel code, but it does not make JavaScript run in parallel.
Understanding this distinction is crucial for:
- performance tuning
- avoiding UI freezes
- writing correct async logic
🧠 The Core Truth
async/awaitis just syntax sugar over Promises.
It makes async code look synchronous, but execution is still single-threaded.
❌ Common Misconception
await fetch("/a");
await fetch("/b");
await fetch("/c");
Many people think:
“These run in parallel because they are async.”
❌ Wrong — they run sequentially.
Each await waits for the previous one to finish before starting the next.
✅ What Actually Runs in Parallel
Only I/O handled by the runtime (browser or Node.js) can run concurrently:
- Network requests
- Timers
- File system operations (Node)
- Database calls
JavaScript code itself never runs in parallel on a single thread.
🔍 What await Really Does
When JavaScript sees:
await promise;
It does three things:
- Pauses the current function
- Returns control to the event loop
- Resumes later when the Promise resolves
➡️ No new thread is created.
➡️ No parallel JS execution happens.
🧪 Sequential vs Concurrent Example
❌ Sequential (slow)
await fetch("/a");
await fetch("/b");
await fetch("/c");
Timeline:
A ───► B ───► C
✅ Concurrent (correct)
const a = fetch("/a");
const b = fetch("/b");
const c = fetch("/c");
await Promise.all([a, b, c]);
Timeline:
A ──────┐
B ──────┼──► await
C ──────┘
Here:
- Requests run concurrently (outside JS)
- JS still resumes once, not in parallel
⚠️ async/await vs CPU Work
This still blocks the UI:
async function bad() {
await heavyCpuTask(); // ❌ still blocks
}
Because:
- CPU-heavy work runs on the JS thread
awaitdoes not offload computation
If you need real parallel CPU work:
- Web Workers (browser)
- Worker Threads (Node.js)
🧠 Mental Model
- async/await = pause & resume
- Promise = future value
- Event loop = scheduler
- Parallelism = multiple threads (JS does not have this)
Think of await as:
“Pause here, let other JS run, come back later.”
🔁 Why async/await Still Feels Faster
Even though it’s not parallel:
- JS thread stays free while waiting
- UI stays responsive
- Multiple I/O tasks overlap
So apps feel faster — but computation is still single-threaded.
🧱 When You Actually Get Parallelism
| Scenario | Parallel? |
|---|---|
await fetch() | ❌ JS / ✅ I/O |
Promise.all(fetches) | ❌ JS / ✅ I/O |
| CPU loop | ❌ |
| Web Worker | ✅ |
| Node worker_threads | ✅ |
✅ Summary
| Concept | Reality |
|---|---|
| async/await | Syntax sugar |
| JS execution | Single-threaded |
| I/O | Concurrent |
| CPU work | Blocking |
| Promise.all | Concurrency, not parallelism |
✨ Final Takeaway
async/await makes asynchronous code readable — not parallel.
For parallel execution, you need multiple threads (workers), not syntax.
Suggested follow-ups
- Event Loop: microtasks vs macrotasks
- Promise.all vs Promise.allSettled vs Promise.race
- Web Workers vs async/await