Skip to main content
Practice Problems

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

FunctionWhen it runsPhase
process.nextTick()After current op, before I/OMicrotask
Promise.then()After nextTickMicrotask
setTimeout(fn, 0)Minimum delay after current cycleTimers
setImmediate()Next iteration, check phaseCheck
setInterval()Repeatedly at intervalTimers

Best practice: Use setImmediate() to break up CPU-intensive work. Use setTimeout() for actual delays. Prefer timers/promises for async/await. Avoid setInterval in server code — use cron libraries or message queues instead.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?
Practice Problems