Node.js Timers and setImmediate — Complete Guide to Timer Scheduling
In this tutorial, you will learn about Node.js Timers and setImmediate. We cover key concepts, practical examples, and best practices to help you master this topic.
Node.js timers schedule callback execution with setTimeout (one-time delay), setInterval (repeating), and setImmediate (check phase), each with distinct event loop placement.
What You'll Learn
By the end of this tutorial, you'll use setTimeout, setInterval, and setImmediate effectively, understand minimum delay behavior, cancel scheduled timers, and avoid common timing pitfalls.
Why Timers Matter
Timers control execution order, implement polling, schedule background tasks, and manage timeouts for external services. Misusing them causes race conditions and performance issues.
Real-World Use
An API Gateway uses setTimeout for request timeouts, setInterval for health check polling every 30 seconds, and setImmediate to defer processing after I/O callbacks.
Timer Learning Path
flowchart LR
A[Event Loop Phases] --> B[Timers]
B --> C[setImmediate]
C --> D[nextTick]
D --> E[Blocking vs Non-Blocking]
B --> F{You Are Here}
style F fill:#f90,color:#fff
setTimeout Basics
setTimeout schedules a callback to run after a minimum delay in milliseconds. The actual delay depends on event loop congestion.
console.log("Start");
const timerId = setTimeout(() => {
console.log("Executed after ~100ms");
}, 100);
console.log("End - timer scheduled");
// Output:
// Start
// End - timer scheduled
// Executed after ~100ms
setInterval Repeating
setInterval schedules a callback to run repeatedly at the specified interval. The delay is between the start of each invocation.
let count = 0;
const intervalId = setInterval(() => {
count++;
console.log(`Interval tick ${count}`);
if (count >= 3) {
clearInterval(intervalId);
console.log("Interval cleared");
}
}, 500);
// Output (500ms apart):
// Interval tick 1
// Interval tick 2
// Interval tick 3
// Interval cleared
setImmediate Placement
setImmediate schedules a callback in the check phase, immediately after the poll phase completes. It runs before any timers scheduled with setTimeout(fn, 0).
const fs = require("node:fs");
fs.readFile(__filename, "utf8", () => {
setImmediate(() => {
console.log("setImmediate: runs after poll in check phase");
});
setTimeout(() => {
console.log("setTimeout: runs in next timers phase");
}, 0);
});
// Output:
// setImmediate: runs after poll in check phase
// setTimeout: runs in next timers phase
Unref and Ref
Unref allows a timer to not keep the event loop running. Ref restores the behavior. Useful for timers that should not prevent Process exit.
const timer = setTimeout(() => {
console.log("This may not run if nothing else keeps the loop alive");
}, 1000);
timer.unref();
console.log("Timer unreffed - process may exit before it fires");
// Timer unreffed - process may exit before it fires
Clearing Timers
Always clear timers when they are no longer needed to prevent memory leaks and unexpected callbacks.
const timeout = setTimeout(() => console.log("Never runs"), 1000);
const interval = setInterval(() => console.log("Never runs"), 1000);
const immediate = setImmediate(() => console.log("Never runs"));
clearTimeout(timeout);
clearInterval(interval);
clearImmediate(immediate);
console.log("All timers cleared");
Common Mistakes
1. Assuming setTimeout(fn, 0) Is Instant
Minimum delay is 1ms (clamped from 0). It still waits for the timers phase.
2. Forgetting to Clear Timers
Uncleared timers keep the event loop alive and cause memory leaks. Always store timer IDs and clear on cleanup.
3. Nested setTimeout vs setInterval
Nested setTimeout guarantees delay between completions. setInterval does not account for execution time.
4. Using setInterval for Precise Timing
setInterval drift accumulates. Use recursive setTimeout for precise intervals by recalculating the delay.
5. Assuming setImmediate Is Faster Than setTimeout(fn, 0)
setImmediate runs in the check phase. setTimeout(fn, 0) waits for the timers phase. Inside I/O, setImmediate wins.
Practice Questions
1. What is the minimum delay for setTimeout?
1ms. Values less than 1 are clamped to 1. Older Node.js versions clamped to 4ms.
2. How does setInterval differ from recursive setTimeout?
setInterval schedules the next invocation based on start time. Recursive setTimeout schedules based on completion time.
3. What does unref() do on a timer?
It allows the process to exit even if the timer is still pending. The timer still fires if the loop is active.
4. In which event loop phase does setImmediate run?
The check phase, which runs immediately after the poll phase.
5. Challenge: Create a precise repeating timer using recursive setTimeout.
function preciseInterval(fn, delay) {
let schedule = () => {
fn();
setTimeout(schedule, delay);
};
setTimeout(schedule, delay);
}
preciseInterval(() => console.log("Tick", Date.now()), 1000);
FAQ
Mini Project: Timer-Based Polling System
Build a service that polls a resource with configurable intervals and timeout protection.
class Poller {
constructor(url, intervalMs = 5000, timeoutMs = 30000) {
this.url = url;
this.intervalMs = intervalMs;
this.timeoutMs = timeoutMs;
this.timer = null;
}
start() {
const poll = () => {
console.log(`Polling ${this.url}...`);
const timeout = setTimeout(() => console.log("Request timed out"), this.timeoutMs);
timeout.unref();
this.timer = setTimeout(poll, this.intervalMs);
};
this.timer = setTimeout(poll, 0);
}
stop() {
clearTimeout(this.timer);
console.log("Polling stopped");
}
}
const poller = new Poller("https://api.example.com/health");
poller.start();
setTimeout(() => poller.stop(), 20000);
What's Next
Node.js process.nextTick Node.js Blocking vs Non-Blocking Node.js Error Handling
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro