Finish the current work before scheduled callbacks
JavaScript runs a piece of synchronous code to completion before it starts another scheduled callback in the same environment. Promise reactions and await continuations use a microtask queue. When current work yields, queued microtasks run before the browser moves to the next timer task. A timer’s delay is a minimum scheduling threshold, not an exact appointment.
setTimeout(callback, milliseconds) schedules a callback and immediately returns a timer handle. clearTimeout(handle) cancels a still-pending timer. Passing zero does not mean “call the callback now.” Avoid using arbitrary sleeps to wait for a request: wait for the request’s actual promise.
new Promise((resolve, reject) => { ... }) adapts a callback-style operation. Its executor runs immediately; resolve fulfills the promise and reject rejects it. Use this when adapting a timer or event, not to wrap every async function in another promise. Await already works on a function returning a promise.
The example joins the timer promise explicitly so the editor knows when the demonstration is complete. In application code, leave long-running work cancellable and avoid blocking loops that prevent other callbacks from running.
Predict and trace
Write the output before running. Follow the values through each call; if your prediction differs, identify the first step that surprised you.
async function main() {
const timer = new Promise(resolve => {
setTimeout(() => {
console.log("timer");
resolve();
}, 0);
});
const reaction = Promise.resolve().then(() => {
console.log("promise");
});
console.log("sync");
await reaction;
await timer;
}
main();Check your prediction
sync
promise
timerThe timer cannot interrupt the current synchronous log. The promise reaction runs at the microtask checkpoint before the timer task.
A zero-delay timer still waits for a turn
Synchronous statements finish before promise reactions and timer callbacks can run. A delay of zero requests a later opportunity; it does not interrupt the current call. Treat timer delays as minimum scheduling requests rather than precise deadlines.
Await pauses its async function, not every other operation. A caller can continue after the async function reaches its first await. To collect all intended output in this editor, return and await the actual work rather than launching it and forgetting it.
async function main() {
const work = Promise.resolve().then(() => console.log("reaction"));
console.log("registered");
await work;
console.log("awaited");
}
main();Check your prediction
registered
reaction
awaited Registering then does not run its callback inline. The statement registered appears before the queued reaction. Awaited is printed only after that particular promise settles.
async function main() {
async function child() {
console.log("child starts");
await Promise.resolve();
console.log("child resumes");
}
const pending = child();
console.log("caller continues");
await pending;
}
main();Check your prediction
child starts
caller continues
child resumes The child runs synchronously until its first await, then yields to its caller. Awaiting pending afterward keeps the caller responsible for completion.
Try the rule on new inputs
Add a log before calling child and another after awaiting it. Predict all five positions. Explain why awaiting Promise.resolve once is not a general method for flushing an arbitrary chain of asynchronous operations.
Build it yourself
Event Loop & Timers: practise
Write delayValue(value), returning a promise that fulfills with value from a timer. Print “Waiting”, await delayValue(“Ready”), then print the returned value.
// Use a short timer; the exact elapsed time is not the contract.Hint 1: the idea
Return a promise that resolves from the timer callback.
Hint 2: a first step
The resolve function accepts the fulfillment value.
Show one solution
async function main() {
function delayValue(value) {
return new Promise(resolve => {
setTimeout(() => resolve(value), 0);
});
}
console.log("Waiting");
console.log(await delayValue("Ready"));
}
main();Waiting
ReadyAdd a synchronous log immediately after creating the promise and before awaiting it. Predict its order. Do not assert that the zero-delay timer took exactly zero milliseconds.
Test a changed requirement
Add a synchronous log immediately after creating the promise and before awaiting it. Predict its order. Do not assert that the zero-delay timer took exactly zero milliseconds.
Explain before moving on
What runs immediately inside a Promise constructor? Why can a busy synchronous loop delay a timer?
Completion is saved in this browser only. It does not measure mastery.