Timers & the Event Loop Phases
Node's timers (setTimeout, setInterval, setImmediate) and process.nextTick are scheduling tools that hand callbacks to specific phases of the event loop, which decides the exact order your asynchronous code runs in.
Learn Timers & the Event Loop Phases in our free Node.js course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a…
Part of the free Node.js course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
By the end of this lesson you'll be able to schedule and cancel timers, predict the precise order of nextTick, promise microtasks, timers, and setImmediate, and explain the event-loop phases that make Node fast and single-threaded.
What You'll Learn in This Lesson
1️⃣ The Timer Functions
Node gives you four scheduling globals that work without any require . setTimeout(fn, ms) runs a callback once after a delay and returns a handle ; pass that handle to clearTimeout to cancel it before it fires. setInterval(fn, ms) repeats forever until you stop it with clearInterval .
The delay is a minimum , not a guarantee: Node will run your callback as soon as it can after that time, once the event loop reaches the timers phase. That's why the 30ms interval below ticks once before the 50ms timeout, then continues.
2️⃣ The Order Everything Runs In
This is the part that trips up even experienced developers. After your synchronous code finishes, Node drains queues in a strict priority order: first the process.nextTick queue, then the promise microtask queue, and only then does the event loop advance to phases like timers ( setTimeout ) and check ( setImmediate ).
The example below schedules one of each, deliberately out of order, then numbers the output so you can see the true sequence. Run it in a .cjs (CommonJS) file to see this canonical ordering.
3️⃣ nextTick Always Beats Timers
The process.nextTick queue has the highest priority of all. Every nextTick callback registered during the current operation runs — to completion — before the event loop is allowed to move to the timers phase, even for a timer that was registered before the nextTick calls.
That power is a double-edged sword: if a nextTick callback schedules another nextTick, which schedules another, you can starve the loop and stop timers and I/O from ever running. Use it sparingly and intentionally.
Your turn. The program below works once you fill in the three blanks marked ___ . Follow the 👉 hints, then run it and compare with the expected output — the order is the whole point.
No blanks this time — just a brief and an outline. Write it yourself, run it, and check your output against the example in the comments. This ties together setInterval and clearInterval in one short program.
📋 Quick Reference — Scheduling & Order
Practice quiz
What does setTimeout(fn, ms) do?
- Runs fn repeatedly every ms
- Runs fn once after at least ms milliseconds
- Runs fn synchronously now
- Cancels a timer
Answer: Runs fn once after at least ms milliseconds. setTimeout schedules fn to run once after the delay (a minimum, not exact).
How do you cancel a pending setTimeout?
- clearTimeout(handle)
- stopTimeout(handle)
- setTimeout(null)
- delete handle
Answer: clearTimeout(handle). Pass the handle setTimeout returned to clearTimeout to cancel it before it fires.
After synchronous code, which queue drains FIRST?
- setTimeout timers
- setImmediate
- process.nextTick
- I/O callbacks
Answer: process.nextTick. The nextTick queue has the highest priority — it drains before microtasks and every phase.
In Node, which runs LAST among these in one turn?
- process.nextTick
- promise .then microtask
- synchronous code
- setImmediate
Answer: setImmediate. Order is sync → nextTick → promise microtasks → timers → setImmediate (check phase).
Why doesn't setTimeout(fn, 0) run immediately?
- It is a macrotask that waits for the timers phase
- It is cancelled automatically
- Zero means never
- It needs a require
Answer: It is a macrotask that waits for the timers phase. It runs after all sync code, nextTicks, and microtasks — it is a macrotask.
How do you stop a repeating setInterval?
- clearTimeout(id)
- clearInterval(id)
- return false
- setInterval(0)
Answer: clearInterval(id). Store the id setInterval returns and pass it to clearInterval.
Which is a microtask in Node?
- setImmediate
- setInterval
- A resolved promise's .then callback
- An fs read callback
Answer: A resolved promise's .then callback. Promise .then/.catch/.finally callbacks are microtasks; timers/immediate are macrotasks.
What risk comes from recursive process.nextTick calls?
- A SyntaxError
- The timer fires twice
- Faster I/O
- They can starve the event loop so timers and I/O never run
Answer: They can starve the event loop so timers and I/O never run. nextTick scheduling more nextTicks blocks the loop from advancing.
Which phase runs setImmediate callbacks?
- The check phase
- The timers phase
- The poll phase
- The close phase
Answer: The check phase. setImmediate callbacks run in the dedicated check phase, after poll.
Do the timer functions need a require in Node?
- Yes, require('timers')
- Only setInterval does
- No — they are global
- Only in ES modules
Answer: No — they are global. setTimeout, setInterval, setImmediate, and clearTimeout are global in Node.