async changes how a program waits and resumes; it does not make computation disappear. To reason about an asynchronous operation, identify which code runs on the JavaScript thread, which work is delegated, and which event later makes a callback runnable.
An await splits a function into parts
When an async function reaches await, it evaluates the awaited expression and suspends that function's continuation. The current JavaScript stack can return to its caller. When the promise settles, the continuation is queued according to the runtime's scheduling rules. The function resumes later; it does not continue running in parallel at the await line.
This makes await useful for structuring asynchronous control flow, but a CPU-heavy loop still blocks whichever thread executes it. A single-threaded event loop cannot process another callback until the current callback yields.
I/O and CPU work take different paths
An operating system may provide non-blocking facilities for network I/O. A runtime registers interest in completion and later schedules a callback. Some APIs use a worker pool for operations that do not have a suitable non-blocking system interface or for expensive work such as certain file-system or cryptographic tasks. The exact implementation is runtime- and platform-dependent.
Node.js combines JavaScript execution with native bindings, the event loop, and a worker pool. Blocking the event loop increases latency for other clients even when the machine has idle cores. Moving CPU-heavy work to worker threads or another service can help, but adds message passing and lifecycle costs.
Diagnose the queue, not the keyword
When a request is slow, ask whether it is waiting for network I/O, queued behind JavaScript, consuming worker-pool capacity, or spending CPU time in one callback. Instrument those boundaries and use representative load. The Node.js guide to the event loop and worker pool explains which work runs where and why long callbacks hurt responsiveness.