How do Timers and scheduling work in Node.js?
Timers in Node.js
Node.js provides several timer functions for scheduling code execution. They integrate with the event loop and execute at different phases.
Timer Functions
setTimeout — Execute once after delay
js
const timer = setTimeout(() => {
console.log('Executed after 2 seconds');
}, 2000);
// Cancel if needed
clearTimeout(timer);setInterval — Execute repeatedly
js
let count = 0;
const interval = setInterval(() => {
console.log(`Tick ${++count}`);
if (count >= 5) clearInterval(interval);
}, 1000);setImmediate — Execute on next event loop iteration
js
setImmediate(() => {
console.log('Runs in the check phase of event loop');
});process.nextTick — Execute before any I/O
js
process.nextTick(() => {
console.log('Runs before any I/O in microtask queue');
});Execution Order
js
console.log('1 - synchronous');
setTimeout(() => console.log('2 - setTimeout'), 0);
setImmediate(() => console.log('3 - setImmediate'));
process.nextTick(() => console.log('4 - nextTick'));
Promise.resolve().then(() => console.log('5 - Promise'));
console.log('6 - synchronous');
// Output:
// 1 - synchronous
// 6 - synchronous
// 4 - nextTick
// 5 - Promise
// 2 - setTimeout (or 3 — order between setTimeout(0) and setImmediate
// 3 - setImmediate // is non-deterministic outside I/O cycle)Timer Accuracy
Timers in Node.js are not exact. They guarantee a minimum delay, not a precise one:
js
const start = Date.now();
setTimeout(() => {
console.log(`Actual delay: ${Date.now() - start}ms`);
// Will be >= 100ms, often 101-105ms
}, 100);Advanced: AbortController with Timers
js
const { setTimeout: sleep } = require('timers/promises');
async function fetchWithTimeout(url, ms) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), ms);
try {
const response = await fetch(url, { signal: controller.signal });
clearTimeout(timeout);
return response;
} catch (err) {
if (err.name === 'AbortError') {
throw new Error(`Request timed out after ${ms}ms`);
}
throw err;
}
}Promisified Timers (Node.js 16+)
js
const { setTimeout, setInterval, setImmediate } = require('timers/promises');
// Await a delay
await setTimeout(1000);
console.log('1 second passed');
// Iterate on interval
const interval = setInterval(1000);
for await (const _ of interval) {
console.log('tick');
break; // stop after first tick
}Common Patterns
Debounce
js
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}Retry with Exponential Backoff
js
async function retryWithBackoff(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (err) {
if (i === maxRetries - 1) throw err;
const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}Summary Table
| Function | When it runs | Phase |
|---|---|---|
process.nextTick() | After current op, before I/O | Microtask |
Promise.then() | After nextTick | Microtask |
setTimeout(fn, 0) | Minimum delay after current cycle | Timers |
setImmediate() | Next iteration, check phase | Check |
setInterval() | Repeatedly at interval | Timers |
Best practice: Use
setImmediate()to break up CPU-intensive work. UsesetTimeout()for actual delays. Prefertimers/promisesfor async/await. AvoidsetIntervalin server code — use cron libraries or message queues instead.
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.