Complete Node.js Timers & Process Tutorial
Scheduling, event loop timing behavior, process lifecycle, signals, and production process control
Scheduling
Event Loop
Process Control
Table of Contents
- Introduction to Timers
- setTimeout & clearTimeout
- setInterval & clearInterval
- setImmediate & clearImmediate
- process.nextTick
- Event Loop Integration
- Process Module Fundamentals
- Process Events & Signals
- Process Input/Output
- Environment & Arguments
- Process Management
- Real-World Examples
- Performance & Best Practices
- Quick Reference
- Interview Q&A + MCQ
1. Introduction to Timers
What are Timers?
Timers schedule code execution in the future. In Node.js, timer APIs and the process object are globally available.
console.log(typeof setTimeout); // 'function'
console.log(typeof setInterval); // 'function'
console.log(typeof setImmediate); // 'function'
console.log(typeof process); // 'object'
Timer Types Overview
| Timer | Execution Time | Use Case |
|---|---|---|
setTimeout | After minimum delay | One-time delayed execution |
setInterval | Repeatedly with delay | Periodic tasks |
setImmediate | After I/O callbacks | Defer and run soon |
process.nextTick | Before next loop phase | High-priority deferral |
2. setTimeout & clearTimeout
Basic Usage
const timeoutId = setTimeout(() => {
console.log('This runs after 2 seconds');
}, 2000);
setTimeout((name, age) => {
console.log(`Hello ${name}, you are ${age} years old`);
}, 1000, 'Alice', 25);
clearTimeout(timeoutId);
Promise Delay + Timeout Wrapper
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function timeoutPromise(promise, ms, message = 'Operation timed out') {
const timeout = new Promise((_, reject) => {
setTimeout(() => reject(new Error(message)), ms);
});
return Promise.race([promise, timeout]);
}
Debounce / Throttle
function debounce(func, delay) {
let timeoutId;
return function (...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(this, args), delay);
};
}
function throttle(func, limit) {
let inThrottle;
return function (...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
3. setInterval & clearInterval
Basic Interval
let count = 0;
const intervalId = setInterval(() => {
count++;
console.log(`Tick ${count}`);
if (count === 5) clearInterval(intervalId);
}, 1000);
Heartbeat Monitor Example
class HeartbeatMonitor {
constructor(expectedInterval = 3000) {
this.expectedInterval = expectedInterval;
this.lastHeartbeat = Date.now();
this.warningThreshold = expectedInterval * 1.5;
this.criticalThreshold = expectedInterval * 2;
}
start() {
this.monitorInterval = setInterval(() => {
const delta = Date.now() - this.lastHeartbeat;
if (delta > this.criticalThreshold) console.error(`CRITICAL: ${delta}ms`);
else if (delta > this.warningThreshold) console.warn(`WARNING: ${delta}ms`);
}, 1000);
}
heartbeat() { this.lastHeartbeat = Date.now(); }
stop() { clearInterval(this.monitorInterval); }
}
Adaptive Interval Pattern
class AdaptiveInterval {
constructor(task, initialInterval = 1000) {
this.task = task;
this.interval = initialInterval;
this.isRunning = false;
}
start() { this.isRunning = true; this.scheduleNext(); }
async scheduleNext() {
if (!this.isRunning) return;
setTimeout(async () => {
const start = Date.now();
await this.task();
const duration = Date.now() - start;
if (duration > this.interval * 0.8) this.interval = Math.min(this.interval * 1.2, 30000);
else if (duration < this.interval * 0.3) this.interval = Math.max(this.interval * 0.8, 100);
this.scheduleNext();
}, this.interval);
}
stop() { this.isRunning = false; }
}
4. setImmediate & clearImmediate
Understanding setImmediate
console.log('1. Sync start');
setTimeout(() => console.log('2. setTimeout(0)'), 0);
setImmediate(() => console.log('3. setImmediate'));
console.log('4. Sync end');
Chunk CPU Work
function processLargeArray(array, chunkSize = 1000) {
let index = 0;
function processChunk() {
const chunk = array.slice(index, index + chunkSize);
chunk.forEach(item => Math.sqrt(item * item));
index += chunkSize;
if (index < array.length) setImmediate(processChunk);
}
processChunk();
}
5. process.nextTick
Execution Priority
console.log('Start');
process.nextTick(() => console.log('nextTick'));
Promise.resolve().then(() => console.log('Promise'));
setTimeout(() => console.log('setTimeout'), 0);
setImmediate(() => console.log('setImmediate'));
console.log('End');
Safe Deferred Emission
class SafeEmitter {
constructor() { this.listeners = new Map(); }
on(event, cb) {
if (!this.listeners.has(event)) this.listeners.set(event, []);
this.listeners.get(event).push(cb);
}
emit(event, data) {
const callbacks = this.listeners.get(event) || [];
process.nextTick(() => callbacks.forEach(cb => cb(data)));
}
}
6. Event Loop Integration
const fs = require('fs');
console.log('1. Main start');
setTimeout(() => console.log('2. Timers phase'), 0);
setImmediate(() => console.log('3. Check phase'));
process.nextTick(() => console.log('4. nextTick microtask'));
Promise.resolve().then(() => console.log('5. Promise microtask'));
fs.readFile(__filename, () => {
console.log('6. Poll (I/O callback)');
setImmediate(() => console.log('7. setImmediate inside I/O'));
});
console.log('8. Main end');
7. Process Module Fundamentals
console.log('PID:', process.pid);
console.log('Platform:', process.platform);
console.log('Node Version:', process.version);
console.log('CWD:', process.cwd());
console.log('Uptime:', process.uptime());
const memoryUsage = process.memoryUsage();
console.log('Heap Used MB:', (memoryUsage.heapUsed / 1024 / 1024).toFixed(2));
const startCPU = process.cpuUsage();
setTimeout(() => {
const cpu = process.cpuUsage(startCPU);
console.log('CPU user ms:', (cpu.user / 1000).toFixed(2));
}, 1000);
8. Process Events & Signals
process.on('exit', (code) => {
console.log(`Exiting with code ${code}`);
});
process.on('uncaughtException', (error) => {
console.error('Uncaught Exception:', error.message);
process.exit(1);
});
process.on('unhandledRejection', (reason) => {
console.error('Unhandled Rejection:', reason);
});
process.on('SIGINT', () => {
console.log('Received SIGINT');
process.exit(0);
});
process.on('SIGTERM', () => {
console.log('Received SIGTERM');
process.exit(0);
});
function sendSignalToProcess(pid, signal = 'SIGTERM') {
try {
process.kill(pid, signal);
return true;
} catch (error) {
console.error(error.message);
return false;
}
}
9. Process Input/Output
process.stdout.write('Custom stdout message\n');
process.stderr.write('Custom stderr message\n');
// Read stdin
process.stdin.setEncoding('utf8');
process.stdin.on('data', (data) => {
const input = data.toString().trim();
if (input === 'exit') process.exit(0);
console.log(`You typed: ${input}`);
});
Interactive CLI Skeleton
class CLI {
constructor() { this.commands = new Map(); }
registerCommand(name, description, handler) {
this.commands.set(name, { description, handler });
}
async runLine(input) {
const [command, ...args] = input.split(' ');
if (this.commands.has(command)) await this.commands.get(command).handler(args);
}
}
10. Process Environment & Arguments
console.log('NODE_ENV:', process.env.NODE_ENV);
console.log('PATH:', process.env.PATH);
const config = {
port: parseInt(process.env.PORT) || 3000,
host: process.env.HOST || 'localhost',
debug: process.env.DEBUG === 'true'
};
function parseArguments() {
const args = process.argv.slice(2);
const parsed = { _: [], flags: {} };
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (arg.startsWith('--')) {
const [key, value] = arg.slice(2).split('=');
parsed.flags[key] = value !== undefined ? value : true;
} else parsed._.push(arg);
}
return parsed;
}
11. Process Management
Graceful Shutdown
class GracefulShutdown {
constructor() {
this.handlers = [];
this.shuttingDown = false;
['SIGINT', 'SIGTERM', 'SIGHUP'].forEach(signal => {
process.on(signal, () => !this.shuttingDown && this.shutdown(signal));
});
}
register(handler) { this.handlers.push(handler); }
async shutdown(signal) {
this.shuttingDown = true;
console.log(`Received ${signal}, shutting down...`);
for (const handler of this.handlers) await handler();
process.exit(0);
}
}
Process Monitor
class ProcessMonitor {
start(intervalMs = 5000) {
this.interval = setInterval(() => {
const m = process.memoryUsage();
console.log('Heap MB:', (m.heapUsed / 1024 / 1024).toFixed(2));
console.log('Uptime:', process.uptime().toFixed(2));
}, intervalMs);
}
stop() { clearInterval(this.interval); }
}
12. Real-World Examples
Example 1: Job Scheduler
class JobScheduler {
constructor() { this.jobs = new Map(); }
schedule(jobName, schedule, task) {
const job = { name: jobName, task, schedule, nextRun: new Date(Date.now() + schedule.interval) };
this.jobs.set(jobName, job);
this.scheduleJob(job);
}
scheduleJob(job) {
const delay = Math.max(0, job.nextRun - new Date());
job.timeoutId = setTimeout(async () => {
await job.task();
job.nextRun = new Date(Date.now() + job.schedule.interval);
this.scheduleJob(job);
}, delay);
}
}
Example 2: Rate Limiter
class RateLimiter {
constructor(windowMs = 60000, maxRequests = 100) {
this.windowMs = windowMs;
this.maxRequests = maxRequests;
this.requests = new Map();
}
isRateLimited(key) {
const now = Date.now();
const timestamps = (this.requests.get(key) || []).filter(ts => now - ts < this.windowMs);
if (timestamps.length >= this.maxRequests) return true;
timestamps.push(now);
this.requests.set(key, timestamps);
return false;
}
}
Example 3: Process Pool Manager
const { fork } = require('child_process');
const os = require('os');
class ProcessPool {
constructor(workerScript, maxWorkers = os.cpus().length) {
this.workerScript = workerScript;
this.maxWorkers = maxWorkers;
this.workers = [];
for (let i = 0; i < maxWorkers; i++) this.workers.push(fork(workerScript));
}
shutdown() { this.workers.forEach(w => w.kill('SIGTERM')); }
}
13. Performance & Best Practices
Best Practices Summary
// DO: setImmediate for deferring I/O callbacks
setImmediate(() => console.log('after I/O callbacks'));
// DO: nextTick for high-priority deferral
process.nextTick(() => console.log('next tick work'));
// DO: clear timers
const id = setInterval(() => {}, 1000);
clearInterval(id);
// DON'T: unbounded recursive nextTick (I/O starvation)
// function bad() { process.nextTick(bad); }
Memory Monitoring Helper
class MemoryManager {
constructor(memoryLimit = 512 * 1024 * 1024, checkInterval = 60000) {
this.memoryLimit = memoryLimit;
this.interval = setInterval(() => {
const heapUsed = process.memoryUsage().heapUsed;
if (heapUsed > this.memoryLimit) console.warn('Memory limit exceeded');
if (global.gc && heapUsed > this.memoryLimit * 0.8) global.gc();
}, checkInterval);
}
stop() { clearInterval(this.interval); }
}
Quick Reference
// Timers
setTimeout(fn, delay, ...args);
setInterval(fn, delay, ...args);
setImmediate(fn, ...args);
process.nextTick(fn, ...args);
clearTimeout(id); clearInterval(id); clearImmediate(id);
// Process
process.pid; process.ppid; process.platform; process.version;
process.memoryUsage(); process.cpuUsage(); process.uptime();
process.env; process.argv;
process.on('exit', cb); process.on('uncaughtException', cb);
process.on('unhandledRejection', cb); process.on('SIGINT', cb);
10 Interview Questions + 10 MCQs
Interview Pattern 10 Q&A1When should you use
setTimeout?easyAnswer: For one-time delayed execution after a minimum delay.
2Difference between
setInterval and recursive setTimeout?mediumAnswer: Recursive timeout allows dynamic delay and avoids overlap when tasks run longer than interval.
3Where does
setImmediate run?mediumAnswer: In the check phase, typically after poll/I/O callbacks.
4Why be careful with
process.nextTick?hardAnswer: Excessive recursive usage can starve I/O and block loop progress.
5How do you cancel scheduled timers?easy
Answer: Use
clearTimeout, clearInterval, and clearImmediate.6What is
process.argv?easyAnswer: Command-line argument array for current process.
7Why handle
SIGINT/SIGTERM?mediumAnswer: To gracefully close resources before process exits.
8What is the purpose of
process.memoryUsage()?mediumAnswer: It reports heap and RSS memory metrics for monitoring/tuning.
9How can you enforce request rate limits?hard
Answer: Use fixed/sliding window or token bucket limiter with timestamp tracking.
10What is graceful shutdown?hard
Answer: Controlled termination that stops intake, flushes work, closes connections, then exits.
10 Timers & Process MCQs
1
Which API schedules one-time delayed work?
Explanation:
setTimeout is for one-time delayed execution.2
Which function cancels intervals?
Explanation: Use
clearInterval to stop repeated callbacks.3
Which callback has highest scheduling priority?
Explanation:
process.nextTick queue runs before loop phases.4
Which process event handles Ctrl+C?
Explanation: Ctrl+C sends
SIGINT.5
Where are CLI args stored?
Explanation: Command-line arguments are available in
process.argv.6
Which API reads env variables?
Explanation: Environment variables live on
process.env.7
When to prefer recursive setTimeout over setInterval?
Explanation: Recursive timeout gives better control over scheduling drift and overlap.
8
Which API gives heap/RSS usage?
Explanation: Use
process.memoryUsage() for memory metrics.9
What is graceful shutdown mainly for?
Explanation: It ensures safe cleanup before termination.
10
Which event handles unhandled promise rejections?
Explanation: Listen to
unhandledRejection on process.