This is a useful place to start when an explanation says JavaScript simply runs every line from top to bottom. Registering a callback and executing its body are different events.
Predict the value as well as the order
Run this original teaching snippet once in a clean browser console. It needs no page elements, network request or library:
(() => {
let label = "before";
console.log("sync-start");
setTimeout(() => console.log("timer", label), 0);
Promise.resolve().then(() => console.log("promise", label));
label = "after";
console.log("sync-end");
})();
The expected message sequence is:
sync-start
sync-end
promise after
timer after
The console may also display the expression's return value, such as undefined. That is separate from these four logged messages.
Both callbacks read label when they run. The assignment to "after" has already happened by then. Neither callback received a frozen copy of "before" merely because it was registered earlier.
Keep the queues separate
The timer is registered before the Promise callback in this snippet, but they do not join one shared first-come-first-served line. In this browser case, the Promise reaction is processed as a microtask after the current synchronous work completes, before the next timer task.
MDN's JavaScript execution model, checked October 24, 2026, explains the engine, host and queued work. The host matters: browser APIs, Node.js-specific queues and module execution can introduce additional rules. State which environment you are reasoning about.
The expected order does not predict an exact elapsed time. A busy main thread and browser timer policies can delay the timer. Adding more asynchronous mechanisms requires another trace; this example does not rank every possible callback source.
Ask ChatGPT for a trace you can check
Explain this exact JavaScript snippet in a normal browser console.
[PASTE THE SNIPPET]
First predict only its console.log message sequence. Then trace:
the synchronous work, when each callback is registered, which
queue it uses, and the value of label when its body actually runs.
Separate the console's expression return value from logged messages.
Explain why the earlier timer registration does not run its callback
before the resolved Promise reaction. Do not invent a measured delay.
Give one small variation that tests the explanation. Do not claim
you ran my browser or rewrite the program into a different example.
OpenAI's prompting guidance supports supplying a concrete example and asking for a specific result. The trace makes it easier to spot an answer that gets the output right for the wrong reason.
Change the value that a callback closes over
Add const captured = label immediately after the initial label declaration, then make the timer log captured instead of label. The timer should now log "before", while the Promise still logs "after". The separate constant preserves that initial string value; the original label variable still changes.
Now move the timer registration below the Promise registration without changing anything else. The original four-message order should remain. This variation checks whether you are reasoning about task types or just source order.
If a real program differs, keep the smallest failing script and its actual environment. Debugging with ChatGPT shows how to turn that mismatch into a testable question. Record observed output separately from a prediction, and preserve the script that produced it.