advanced
Async bottlenecks
Find promise waterfalls, serial loops, unbounded concurrency, blocked event-loop work, and slow queue consumers.
Async bottlenecks in Node.js come from misuse of non-blocking APIs: promise waterfalls, serial `for` loops with await, unbounded concurrency, blocking the event loop with sync crypto/JSON, or slow consumers on streams/queues.
// Bad: serial awaits
for (const id of ids) await fetchOne(id);
// Better: bounded concurrency
await mapPool(ids, 10, (id) => fetchOne(id));
| Smell | Fix | |-------|-----| | Promise waterfall | Parallelize independent steps | | Unbounded `Promise.all` | Semaphore / pool limit | | Sync `fs.readFileSync` | Async APIs or worker threads | | Missing backpressure | Pause streams when buffer full |
Use `performance.eventLoopUtilization` and APM to spot event-loop stall. CPU-heavy work belongs in worker threads or separate services.
On interviews: concurrency limits; difference between parallel and serial async; why `setImmediate` does not fix CPU blocking; queue consumer lag.
Common pitfalls: `await` inside tight loops; mixing sync and async file APIs; ignoring downstream 429/503 as backpressure signals.
The trade-off is simpler sequential code versus throughput and fairness under load.
Checklist:
- Bound parallel async work.
- Keep event loop free of sync CPU spikes.
- Propagate timeouts and cancellation.
- Measure consumer lag on queues.