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

  1. Introduction to Timers
  2. setTimeout & clearTimeout
  3. setInterval & clearInterval
  4. setImmediate & clearImmediate
  5. process.nextTick
  6. Event Loop Integration
  7. Process Module Fundamentals
  8. Process Events & Signals
  9. Process Input/Output
  10. Environment & Arguments
  11. Process Management
  12. Real-World Examples
  13. Performance & Best Practices
  14. Quick Reference
  15. 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

TimerExecution TimeUse Case
setTimeoutAfter minimum delayOne-time delayed execution
setIntervalRepeatedly with delayPeriodic tasks
setImmediateAfter I/O callbacksDefer and run soon
process.nextTickBefore next loop phaseHigh-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&A
1When should you use setTimeout?easy
Answer: For one-time delayed execution after a minimum delay.
2Difference between setInterval and recursive setTimeout?medium
Answer: Recursive timeout allows dynamic delay and avoids overlap when tasks run longer than interval.
3Where does setImmediate run?medium
Answer: In the check phase, typically after poll/I/O callbacks.
4Why be careful with process.nextTick?hard
Answer: 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?easy
Answer: Command-line argument array for current process.
7Why handle SIGINT/SIGTERM?medium
Answer: To gracefully close resources before process exits.
8What is the purpose of process.memoryUsage()?medium
Answer: 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?

AsetInterval
BsetTimeout
CsetImmediate
DnextTick
Explanation: setTimeout is for one-time delayed execution.
2

Which function cancels intervals?

AclearTimeout
BclearImmediate
CclearInterval
DcancelInterval
Explanation: Use clearInterval to stop repeated callbacks.
3

Which callback has highest scheduling priority?

AsetTimeout(0)
BsetImmediate
Cprocess.nextTick
DPromise.then
Explanation: process.nextTick queue runs before loop phases.
4

Which process event handles Ctrl+C?

ASIGINT
BSIGPIPE
CEXITINT
DTERMINATE
Explanation: Ctrl+C sends SIGINT.
5

Where are CLI args stored?

Aprocess.args
Bprocess.argv
Cprocess.params
Dprocess.cli
Explanation: Command-line arguments are available in process.argv.
6

Which API reads env variables?

Aprocess.environment
Bprocess.env
Cenv.process
Dprocess.getEnv()
Explanation: Environment variables live on process.env.
7

When to prefer recursive setTimeout over setInterval?

ANever
BFor variable delay / avoid overlap
COnly browser code
DOnly for CPU tasks
Explanation: Recursive timeout gives better control over scheduling drift and overlap.
8

Which API gives heap/RSS usage?

Aprocess.cpuUsage()
Bprocess.memoryUsage()
Cprocess.resource()
Dprocess.stats()
Explanation: Use process.memoryUsage() for memory metrics.
9

What is graceful shutdown mainly for?

AFaster startup
BCleaning resources before exit
CSkip error handling
DChange Node version
Explanation: It ensures safe cleanup before termination.
10

Which event handles unhandled promise rejections?

ApromiseError
Brejection
CunhandledRejection
DuncaughtPromise
Explanation: Listen to unhandledRejection on process.