This trace follows the actual state transitions behind the companion Async Code Still Runs on an Event Loop. It describes a common execution path; implementation details can vary, so keep the contract separate from the mechanism.
Step 1: Submit asynchronous work
An event loop repeatedly selects ready work and runs callbacks or tasks. Asynchronous I/O lets a program arrange for completion to be reported later so the thread can do other work meanwhile. The syntax may look sequential, but the runtime schedules continuations according to its queues and rules.
Step 2: Register its completion
When a Node.js handler starts a network request, the runtime registers work with the operating system or an internal pool. The JavaScript callback runs after completion is reported and scheduled. A long synchronous calculation inside one callback still occupies the event-loop thread and delays unrelated requests.
Step 3: Run other ready callbacks
When I/O completes, the runtime schedules its continuation; synchronous CPU-heavy work inside a callback still occupies the event-loop thread and delays other ready tasks.
At this point, record the state that changed and check the invariant before advancing. If the operation repeats, make clear which values persist and which are recomputed.
Step 4: Schedule the continuation
Async does not mean parallel, and adding await does not make CPU-heavy work nonblocking. Queue ordering differs across runtimes and task classes. Unhandled rejections, cancellation, and timeouts need explicit policies so stalled work does not linger indefinitely.
Step 5: Send or consume the result
A service has fast network I/O but slow response times whenever it generates a large report. Explain how an event-loop blocker creates that symptom and how you would move or divide the computation.
The trace is complete when the result satisfies the stated contract. Compare this model with the concrete runtime or system you are studying before making a performance claim.