
Node.js, a powerful JavaScript runtime, is crucial for building scalable server-side applications, making it an essential skill for backend developers and DevOps engineers. Stark.ai offers a curated collection of Node.js interview questions, real-world scenarios, and expert guidance to help you excel in your next technical interview.
Node.js is an open-source, cross-platform JavaScript runtime environment that executes JavaScript code outside of a...
Node.js architecture consists of several key components: 1) V8 Engine: Google's open-source JavaScript engine that...
Key differences include: 1) Global object: 'window' in browsers vs 'global' in Node.js, 2) DOM/BOM APIs only...
Node.js handles concurrent requests through: 1) Event Loop: Single-threaded loop that processes async operations, 2)...
libuv is a multi-platform support library that handles: 1) Asynchronous I/O operations, 2) Thread pool management,...
In Node.js: 1) Process: Instance of a program in execution with its own memory space, 2) Main Thread: Single thread...
Core modules are built-in modules that come with Node.js installation: 1) No installation required (http, fs, path),...
CommonJS implementation in Node.js includes: 1) require() function for module loading, 2) module.exports for...
The process object provides information and control over the Node.js process: 1) Environment variables...
Node.js uses V8's garbage collection with two main phases: 1) Scavenge: Fast but partial collection for young...
Error handling in Node.js includes: 1) Try-catch blocks for synchronous code, 2) Error events for EventEmitter, 3)...
V8 Engine in Node.js: 1) Compiles JavaScript to machine code, 2) Manages memory allocation, 3) Handles garbage...
REPL (Read-Eval-Print-Loop) provides an interactive shell for Node.js: 1) Testing code snippets, 2) Debugging, 3)...
ES modules support in Node.js includes: 1) .mjs extension for ES module files, 2) 'type': 'module' in package.json,...
Buffers handle binary data in Node.js: 1) Buffer: Node.js specific for binary data, 2) ArrayBuffer: JavaScript...
Clustering enables running multiple Node.js processes: 1) Master process creates worker processes, 2) Workers share...
Key differences include: 1) LTS (Long Term Support): Stable, production-ready, 30-month support cycle, 2) Current:...
Child processes in Node.js: 1) spawn(): Streams for large data, 2) exec(): Buffers for completion, 3) fork(): IPC...
Timing functions in Node.js: 1) process.nextTick(): Executes callback before next event loop iteration, 2)...
The Event Loop is the mechanism that allows Node.js to perform non-blocking I/O operations despite JavaScript being...
Different asynchronous patterns in Node.js serve different purposes: 1) Callbacks: Traditional pattern with...
The microtask queue handles high-priority tasks like Promise callbacks and process.nextTick. Characteristics: 1)...
Error handling in async operations can be done through multiple patterns: 1) Callbacks: Use error-first pattern....
EventEmitter implements the Observer pattern for event-driven programming. Features: 1) Register event listeners, 2)...
Node.js provides several strategies for CPU-intensive tasks: 1) Worker Threads: Parallel execution of CPU tasks....
Best practices for Promise chains include: 1) Always return values in .then(), 2) Use single catch at the end, 3)...
Custom async iterators can be implemented using Symbol.asyncIterator: Example: class AsyncRange { constructor(start,...
Key differences: 1) Parallel: Multiple tasks execute simultaneously (Worker Threads, Child Processes), 2)...
Async error handling patterns include: 1) Try-catch with async/await. Example: async function handle() { try { await...
Node.js timer functions work through: 1) Timer phase in event loop, 2) Min heap data structure for efficient timer...
Async hooks track lifecycle of async operations: 1) init: Resource creation, 2) before: Callback execution start, 3)...
Custom promises can be implemented using the Promise constructor: Example: function customPromise(value) { return...
Promise execution phases include: 1) Pending: Initial state, 2) Fulfilled: Successful completion, 3) Rejected: Error...
Throttling and debouncing control function execution frequency: 1) Throttle: Limit execution rate. Example: function...
Race conditions can be handled through: 1) Promise.race() for first completion, 2) Mutex implementation for...
Event loop starvation occurs when CPU-intensive tasks block the event loop from processing other events. Prevention...
Cancellable promises can be implemented using: 1) AbortController for fetch operations, 2) Custom cancel tokens, 3)...
Patterns for concurrent database operations include: 1) Connection pooling, 2) Transaction management, 3) Batch...
Retry mechanisms can be implemented using: 1) Exponential backoff, 2) Maximum retry limits, 3) Retry delay...
Memory leak prevention strategies include: 1) Proper event listener cleanup, 2) Closing resources (files,...
Async iterators can be implemented using Symbol.asyncIterator: Example: class DataSource { constructor(data) {...
Rate limiting patterns include: 1) Token bucket algorithm, 2) Sliding window, 3) Fixed window counting, 4) Leaky...
Timeout handling includes: 1) Promise race with timeout promise, 2) AbortController integration, 3) Cleanup on...
Async dependency injection patterns include: 1) Factory functions, 2) Async constructors, 3) Dependency containers....
Distributed event patterns include: 1) Message queues, 2) Pub/sub systems, 3) Event buses, 4) Webhook...
Async middleware patterns include: 1) Pipeline pattern, 2) Chain of responsibility, 3) Composition pattern. Example:...
Backpressure handling strategies include: 1) Implementing pause/resume mechanisms, 2) Buffer size limits, 3)...
Async error boundaries can be implemented using: 1) Higher-order functions, 2) Class wrappers, 3) Decorator...
Node.js supports multiple module systems: 1) CommonJS (require/exports): Traditional Node.js module system. Example:...
Node.js module resolution follows these steps: 1) Core modules (like 'fs'), 2) Local modules with relative paths...
package.json is a project manifest file containing: 1) Basic info (name, version, description), 2) Dependencies...
NPM dependency management includes: 1) Installing packages: npm install package-name, 2) Saving dependencies: --save...
Peer dependencies specify packages that must be installed by the consuming application. Used when: 1) Creating...
Circular dependencies can be handled through: 1) Restructuring code to avoid cycles, 2) Using dependency injection,...
NPM workspaces enable managing multiple packages in a single repository: 1) Define workspaces in root package.json,...
Module loading optimization techniques: 1) Use module caching effectively, 2) Implement lazy loading, 3) Bundle...
Package versioning methods include: 1) Semantic Versioning (MAJOR.MINOR.PATCH), 2) Version ranges (^, ~, *, x), 3)...
Package publishing process: 1) Prepare package.json (name, version, files), 2) Create npm account, 3) npm login, 4)...
package-lock.json ensures consistent installs across environments by: 1) Locking exact versions of dependencies, 2)...
Native modules management includes: 1) node-gyp for compilation, 2) Binary distribution using prebuilt packages, 3)...
Security practices include: 1) Regular security audits (npm audit), 2) Version pinning for critical dependencies, 3)...
Module mocking approaches: 1) Jest mock functions, 2) Proxyquire for dependency injection, 3) Manual mocking....
Module scoping patterns include: 1) IIFE (Immediately Invoked Function Expression), 2) Revealing Module Pattern, 3)...
Environment-specific dependency management: 1) Development vs production dependencies, 2) Optional dependencies, 3)...
Node.js is an open-source, cross-platform JavaScript runtime environment that executes JavaScript code outside of a web browser. Key features include: 1) Event-driven and non-blocking I/O model, 2) Single-threaded event loop with asynchronous programming, 3) NPM (Node Package Manager) for package management, 4) Built-in modules for file system operations, networking, etc., 5) Cross-platform support, 6) Active community and extensive ecosystem.
Node.js architecture consists of several key components: 1) V8 Engine: Google's open-source JavaScript engine that compiles JS to native machine code, 2) libuv: Handles async operations, event loop, and thread pool, 3) Core Modules: Built-in modules like http, fs, path, 4) Node Standard Library: JavaScript implementation of core functionality, 5) Node Package Manager (NPM): Package management system. This architecture enables efficient, non-blocking operations and cross-platform compatibility.
Key differences include: 1) Global object: 'window' in browsers vs 'global' in Node.js, 2) DOM/BOM APIs only available in browsers, 3) File system access available in Node.js but not browsers, 4) Module systems: CommonJS in Node.js vs ES Modules in modern browsers, 5) Threading: Web Workers in browsers vs Worker Threads in Node.js, 6) Different security models and constraints. Understanding these differences is crucial for Node.js development.
Node.js handles concurrent requests through: 1) Event Loop: Single-threaded loop that processes async operations, 2) Thread Pool: Handles CPU-intensive tasks and I/O operations, 3) Non-blocking I/O: Async operations don't block the main thread, 4) Callback Queue: Manages completed async operations, 5) Worker Threads: For CPU-intensive tasks. Example: server.on('request', (req, res) => { // Async operation db.query('SELECT * FROM users', (err, results) => { res.end(JSON.stringify(results)); }); });
libuv is a multi-platform support library that handles: 1) Asynchronous I/O operations, 2) Thread pool management, 3) Event loop implementation, 4) Network operations, 5) File system operations, 6) Inter-process communication. It abstracts underlying OS differences and provides a consistent async I/O interface across platforms. Example: const fs = require('fs'); fs.readFile('file.txt', (err, data) => {}); // handled by libuv behind the scenes
In Node.js: 1) Process: Instance of a program in execution with its own memory space, 2) Main Thread: Single thread running event loop, 3) Worker Threads: Additional threads for CPU-intensive tasks, 4) Thread Pool: Managed by libuv for async operations. Example using worker threads: const { Worker } = require('worker_threads'); const worker = new Worker('./worker.js'); worker.postMessage('start'); worker.on('message', (result) => console.log(result));
Core modules are built-in modules that come with Node.js installation: 1) No installation required (http, fs, path), 2) Higher performance as they're preloaded, 3) Fundamental functionality implementation, 4) Written in C++ for performance. External modules are third-party modules installed via NPM. Example: const http = require('http'); // core module vs const express = require('express'); // external module
CommonJS implementation in Node.js includes: 1) require() function for module loading, 2) module.exports for exposing functionality, 3) Module caching for performance, 4) Module resolution algorithm. Example: // math.js module.exports = { add: (a, b) => a + b }; // main.js const math = require('./math'); console.log(math.add(2, 3)); // Module loading is synchronous and cached
The process object provides information and control over the Node.js process: 1) Environment variables (process.env), 2) Command line arguments (process.argv), 3) Process control (process.exit()), 4) Event handling for process lifecycle, 5) CPU and memory usage information. Example: process.on('uncaughtException', (err) => { console.error('Uncaught Exception:', err); process.exit(1); });
Node.js uses V8's garbage collection with two main phases: 1) Scavenge: Fast but partial collection for young objects, 2) Mark-Sweep: Complete collection for old objects. Features include: 1) Generational collection, 2) Incremental marking, 3) Concurrent sweeping, 4) Memory optimization flags. Example of manual GC trigger (not recommended): global.gc(); // requires --expose-gc flag
Error handling in Node.js includes: 1) Try-catch blocks for synchronous code, 2) Error events for EventEmitter, 3) Error-first callbacks for async operations, 4) Promise rejection handling, 5) Global error handlers. Example: process.on('unhandledRejection', (reason, promise) => { console.log('Unhandled Rejection at:', promise, 'reason:', reason); }); try { throw new Error('Sync Error'); } catch (err) { console.error(err); }
V8 Engine in Node.js: 1) Compiles JavaScript to machine code, 2) Manages memory allocation, 3) Handles garbage collection, 4) Provides data types and objects, 5) Optimizes code execution. Features include: JIT compilation, inline caching, hidden classes for optimization. Example of V8 flags: node --v8-options --optimize_for_size --max_old_space_size=1024 app.js
REPL (Read-Eval-Print-Loop) provides an interactive shell for Node.js: 1) Testing code snippets, 2) Debugging, 3) Experimenting with Node.js features, 4) Quick prototyping. Features include: Auto-completion, Multi-line editing, Command history. Example: node // enters REPL > const sum = (a, b) => a + b; > sum(2, 3) // 5
ES modules support in Node.js includes: 1) .mjs extension for ES module files, 2) 'type': 'module' in package.json, 3) Import/export syntax, 4) Dynamic imports, 5) Module resolution rules. Example: // file.mjs export const hello = 'world'; import { hello } from './file.mjs'; // Dynamic import: const module = await import('./module.mjs');
Buffers handle binary data in Node.js: 1) Buffer: Node.js specific for binary data, 2) ArrayBuffer: JavaScript standard binary data container. Features: Direct memory allocation, Binary data operations, Encoding conversions. Example: const buf = Buffer.from('Hello', 'utf8'); console.log(buf); // <Buffer 48 65 6c 6c 6f> console.log(buf.toString()); // Hello
Clustering enables running multiple Node.js processes: 1) Master process creates worker processes, 2) Workers share server ports, 3) Load balancing between workers, 4) IPC communication between processes. Example: const cluster = require('cluster'); if (cluster.isMaster) { cluster.fork(); cluster.fork(); } else { require('./server.js'); }
Key differences include: 1) LTS (Long Term Support): Stable, production-ready, 30-month support cycle, 2) Current: Latest features, shorter support cycle, potentially unstable. LTS focuses on stability and security, while Current provides newest features. Release schedule: New major version every 6 months, LTS versions released yearly.
Child processes in Node.js: 1) spawn(): Streams for large data, 2) exec(): Buffers for completion, 3) fork(): IPC channel for Node.js processes, 4) execFile(): Execute executable files. Example: const { spawn } = require('child_process'); const ls = spawn('ls', ['-l']); ls.stdout.on('data', (data) => console.log(data.toString()));
Timing functions in Node.js: 1) process.nextTick(): Executes callback before next event loop iteration, 2) setImmediate(): Executes in check phase of event loop. Key differences: nextTick has higher priority and runs before I/O events. Example: process.nextTick(() => console.log('nextTick')); setImmediate(() => console.log('setImmediate'));
The Event Loop is the mechanism that allows Node.js to perform non-blocking I/O operations despite JavaScript being single-threaded. It works in phases: 1) Timers (setTimeout, setInterval), 2) Pending callbacks (I/O callbacks), 3) Idle, prepare (internal use), 4) Poll (new I/O events), 5) Check (setImmediate), 6) Close callbacks. Each phase has a FIFO queue of callbacks to execute. Example: console.log('1'); setTimeout(() => console.log('2'), 0); Promise.resolve().then(() => console.log('3')); console.log('4'); // Output: 1, 4, 3, 2
Different asynchronous patterns in Node.js serve different purposes: 1) Callbacks: Traditional pattern with error-first callback style. Example: fs.readFile('file.txt', (err, data) => {}). 2) Promises: Chain-able operations with .then() and .catch(). Example: fetch('url').then(res => res.json()). 3) Async/Await: Syntactic sugar over promises for cleaner code. Example: async function getData() { const response = await fetch('url'); return response.json(); }. Async/await provides better error handling and code readability compared to callbacks and raw promises.
The microtask queue handles high-priority tasks like Promise callbacks and process.nextTick. Characteristics: 1) Processes before the next event loop phase, 2) Higher priority than macrotasks (setTimeout, setInterval), 3) Includes Promise callbacks and process.nextTick callbacks. Example: process.nextTick(() => console.log('1')); Promise.resolve().then(() => console.log('2')); setTimeout(() => console.log('3'), 0); // Output: 1, 2, 3
Error handling in async operations can be done through multiple patterns: 1) Callbacks: Use error-first pattern. Example: fs.readFile('file.txt', (err, data) => { if (err) handle(err); }). 2) Promises: Use .catch() or try/catch with async/await. Example: async function readFile() { try { const data = await fs.promises.readFile('file.txt'); } catch (err) { handle(err); } }. 3) Event emitters: Use error event handlers. Example: stream.on('error', (err) => handle(err));
EventEmitter implements the Observer pattern for event-driven programming. Features: 1) Register event listeners, 2) Emit events, 3) Handle events asynchronously, 4) Multiple listeners per event. Example: const EventEmitter = require('events'); class MyEmitter extends EventEmitter {} const myEmitter = new MyEmitter(); myEmitter.on('event', (data) => console.log(data)); myEmitter.emit('event', 'Hello World');
Node.js provides several strategies for CPU-intensive tasks: 1) Worker Threads: Parallel execution of CPU tasks. Example: const { Worker } = require('worker_threads'); const worker = new Worker('./worker.js'); 2) Child Processes: Separate Node.js processes. Example: const { fork } = require('child_process'); const child = fork('cpu_task.js'); 3) Chunking: Breaking large tasks into smaller ones. Example: function processChunk(data, callback) { setImmediate(() => { /* process chunk */ callback(); }); }
Best practices for Promise chains include: 1) Always return values in .then(), 2) Use single catch at the end, 3) Avoid nesting promises, 4) Use Promise.all() for parallel operations, 5) Handle rejections properly. Example: fetchUser(id).then(user => { return fetchPosts(user.id); }).then(posts => { return processPosts(posts); }).catch(error => { handleError(error); });
Custom async iterators can be implemented using Symbol.asyncIterator: Example: class AsyncRange { constructor(start, end) { this.start = start; this.end = end; } async *[Symbol.asyncIterator]() { for(let i = this.start; i <= this.end; i++) { await new Promise(resolve => setTimeout(resolve, 1000)); yield i; } } } async function iterate() { for await (const num of new AsyncRange(1, 3)) { console.log(num); } }
Key differences: 1) Parallel: Multiple tasks execute simultaneously (Worker Threads, Child Processes), 2) Concurrent: Tasks progress simultaneously but execute on single thread (async/await, Promises). Example of parallel: const { Worker } = require('worker_threads'); const workers = [new Worker('./worker.js'), new Worker('./worker.js')]; Example of concurrent: async function concurrent() { const [result1, result2] = await Promise.all([task1(), task2()]); }
Async error handling patterns include: 1) Try-catch with async/await. Example: async function handle() { try { await riskyOperation(); } catch (err) { handleError(err); } } 2) Error boundaries: class ErrorBoundary extends EventEmitter { async execute(fn) { try { return await fn(); } catch (err) { this.emit('error', err); } } } 3) Error-first callbacks: function operation(callback) { doAsync((err, result) => callback(err, result)); }
Node.js timer functions work through: 1) Timer phase in event loop, 2) Min heap data structure for efficient timer management, 3) Internal scheduling using libuv. Example: const start = Date.now(); setTimeout(() => console.log(Date.now() - start), 1000); // Actual delay might be longer due to event loop phases and CPU load. setTimeout and setInterval are not exact timing mechanisms.
Async hooks track lifecycle of async operations: 1) init: Resource creation, 2) before: Callback execution start, 3) after: Callback completion, 4) destroy: Resource cleanup. Example: const async_hooks = require('async_hooks'); const hook = async_hooks.createHook({ init(asyncId, type) { console.log(`${type}: ${asyncId}`); }, destroy(asyncId) { console.log(`Destroyed: ${asyncId}`); } }).enable();
Custom promises can be implemented using the Promise constructor: Example: function customPromise(value) { return new Promise((resolve, reject) => { if (value) { setTimeout(() => resolve(value), 1000); } else { reject(new Error('Invalid value')); } }); } class AsyncOperation { static async execute() { return new Promise((resolve, reject) => { // Async operation logic }); } }
Promise execution phases include: 1) Pending: Initial state, 2) Fulfilled: Successful completion, 3) Rejected: Error state. Methods: .then() for fulfillment, .catch() for rejection, .finally() for cleanup. Example: new Promise((resolve, reject) => { doAsync() }).then(result => { // Fulfilled }).catch(error => { // Rejected }).finally(() => { // Cleanup });
Throttling and debouncing control function execution frequency: 1) Throttle: Limit execution rate. Example: function throttle(fn, delay) { let last = 0; return function(...args) { const now = Date.now(); if (now - last >= delay) { last = now; return fn.apply(this, args); } }; } 2) Debounce: Delay execution until pause. Example: function debounce(fn, delay) { let timeoutId; return function(...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() => fn.apply(this, args), delay); }; }
Race conditions can be handled through: 1) Promise.race() for first completion, 2) Mutex implementation for synchronization, 3) Atomic operations, 4) Proper state management. Example: class Mutex { constructor() { this.locked = false; this.queue = []; } async acquire() { return new Promise(resolve => { if (!this.locked) { this.locked = true; resolve(); } else { this.queue.push(resolve); } }); } release() { if (this.queue.length > 0) { const next = this.queue.shift(); next(); } else { this.locked = false; } } }
Event loop starvation occurs when CPU-intensive tasks block the event loop from processing other events. Prevention methods include: 1) Breaking long tasks into smaller chunks using setImmediate, 2) Using Worker Threads for CPU-intensive work, 3) Implementing proper concurrency controls. Example: function processArray(arr) { let index = 0; function nextChunk() { if (index < arr.length) { let chunk = arr.slice(index, index + 1000); // Process chunk setImmediate(() => nextChunk()); // Schedule next chunk index += 1000; } } nextChunk(); }
Cancellable promises can be implemented using: 1) AbortController for fetch operations, 2) Custom cancel tokens, 3) Wrapper classes with cancel functionality. Example: class CancellablePromise { constructor(executor) { this.abortController = new AbortController(); this.promise = new Promise((resolve, reject) => { executor(resolve, reject, this.abortController.signal); }); } cancel() { this.abortController.abort(); } } const operation = new CancellablePromise((resolve, reject, signal) => { signal.addEventListener('abort', () => reject(new Error('Cancelled'))); });
Patterns for concurrent database operations include: 1) Connection pooling, 2) Transaction management, 3) Batch operations, 4) Rate limiting. Example: class DBOperations { constructor(pool) { this.pool = pool; } async batchInsert(records, batchSize = 1000) { for (let i = 0; i < records.length; i += batchSize) { const batch = records.slice(i, i + batchSize); await Promise.all(batch.map(record => this.insert(record))); } } async transaction(operations) { const client = await this.pool.connect(); try { await client.query('BEGIN'); const results = await Promise.all(operations.map(op => op(client))); await client.query('COMMIT'); return results; } catch (e) { await client.query('ROLLBACK'); throw e; } finally { client.release(); } } }
Retry mechanisms can be implemented using: 1) Exponential backoff, 2) Maximum retry limits, 3) Retry delay calculation, 4) Error type checking. Example: async function retry(operation, maxRetries = 3, delay = 1000) { for (let i = 0; i < maxRetries; i++) { try { return await operation(); } catch (error) { if (i === maxRetries - 1) throw error; const waitTime = delay * Math.pow(2, i); await new Promise(resolve => setTimeout(resolve, waitTime)); } } }
Memory leak prevention strategies include: 1) Proper event listener cleanup, 2) Closing resources (files, connections), 3) Monitoring reference counts, 4) Using WeakMap/WeakSet. Example: class ResourceManager { constructor() { this.resources = new WeakMap(); } async useResource(key, resource) { try { this.resources.set(key, resource); await resource.process(); } finally { resource.close(); // Cleanup this.resources.delete(key); } } }
Async iterators can be implemented using Symbol.asyncIterator: Example: class DataSource { constructor(data) { this.data = data; } async *[Symbol.asyncIterator]() { for (const item of this.data) { await new Promise(resolve => setTimeout(resolve, 100)); yield item; } } } async function processData() { const source = new DataSource([1, 2, 3]); for await (const item of source) { console.log(item); } }
Rate limiting patterns include: 1) Token bucket algorithm, 2) Sliding window, 3) Fixed window counting, 4) Leaky bucket algorithm. Example: class RateLimiter { constructor(limit, interval) { this.limit = limit; this.interval = interval; this.tokens = limit; this.lastRefill = Date.now(); } async acquire() { const now = Date.now(); const timePassed = now - this.lastRefill; this.tokens += Math.floor(timePassed / this.interval) * this.limit; this.tokens = Math.min(this.tokens, this.limit); this.lastRefill = now; if (this.tokens <= 0) { throw new Error('Rate limit exceeded'); } this.tokens--; return true; } }
Timeout handling includes: 1) Promise race with timeout promise, 2) AbortController integration, 3) Cleanup on timeout. Example: function withTimeout(promise, timeout) { const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error('Operation timed out')), timeout); }); return Promise.race([promise, timeoutPromise]); } async function fetchWithTimeout(url, timeout = 5000) { const controller = new AbortController(); const id = setTimeout(() => controller.abort(), timeout); try { const response = await fetch(url, { signal: controller.signal }); clearTimeout(id); return response; } catch (err) { clearTimeout(id); throw err; } }
Async dependency injection patterns include: 1) Factory functions, 2) Async constructors, 3) Dependency containers. Example: class Container { constructor() { this.dependencies = new Map(); } async register(key, factory) { this.dependencies.set(key, factory); } async resolve(key) { const factory = this.dependencies.get(key); if (!factory) throw new Error(`No dependency found for ${key}`); return await factory(); } } class Service { static async create(container) { const dependency = await container.resolve('dependency'); return new Service(dependency); } }
Distributed event patterns include: 1) Message queues, 2) Pub/sub systems, 3) Event buses, 4) Webhook implementations. Example: class DistributedEventEmitter { constructor(redis) { this.redis = redis; this.handlers = new Map(); this.redis.subscribe('events'); this.redis.on('message', (channel, message) => { const event = JSON.parse(message); const handlers = this.handlers.get(event.type) || []; handlers.forEach(handler => handler(event.data)); }); } on(eventType, handler) { const handlers = this.handlers.get(eventType) || []; handlers.push(handler); this.handlers.set(eventType, handlers); } emit(eventType, data) { this.redis.publish('events', JSON.stringify({ type: eventType, data })); } }
Async middleware patterns include: 1) Pipeline pattern, 2) Chain of responsibility, 3) Composition pattern. Example: class MiddlewareChain { constructor() { this.middlewares = []; } use(middleware) { this.middlewares.push(middleware); return this; } async execute(context) { return this.middlewares.reduce((promise, middleware) => { return promise.then(() => middleware(context)); }, Promise.resolve()); } } const chain = new MiddlewareChain(); chain.use(async (ctx) => { ctx.validated = true; }).use(async (ctx) => { if (ctx.validated) ctx.processed = true; });
Backpressure handling strategies include: 1) Implementing pause/resume mechanisms, 2) Buffer size limits, 3) Throttling, 4) Flow control. Example: class ThrottledStream extends Readable { constructor(source, rate) { super(); this.source = source; this.rate = rate; this.lastRead = Date.now(); } _read(size) { const now = Date.now(); const timeSinceLastRead = now - this.lastRead; if (timeSinceLastRead < this.rate) { setTimeout(() => this._read(size), this.rate - timeSinceLastRead); return; } this.lastRead = now; const chunk = this.source.read(size); this.push(chunk); } }
Async error boundaries can be implemented using: 1) Higher-order functions, 2) Class wrappers, 3) Decorator patterns. Example: class AsyncBoundary { constructor(errorHandler) { this.errorHandler = errorHandler; } wrap(target) { return new Proxy(target, { get: (obj, prop) => { const value = obj[prop]; if (typeof value === 'function') { return async (...args) => { try { return await value.apply(obj, args); } catch (error) { return this.errorHandler(error); } }; } return value; } }); } } const safeFetch = new AsyncBoundary(error => console.error(error)) .wrap({ async fetch(url) { const response = await fetch(url); return response.json(); } });
Node.js supports multiple module systems: 1) CommonJS (require/exports): Traditional Node.js module system. Example: const fs = require('fs'); module.exports = { ... }. 2) ES Modules (import/export): Modern JavaScript module system. Example: import fs from 'fs'; export const handler = { ... }. 3) ECMAScript Modules in Node.js require either .mjs extension or { 'type': 'module' } in package.json.
Node.js module resolution follows these steps: 1) Core modules (like 'fs'), 2) Local modules with relative paths ('./myModule'), 3) node_modules lookup (starts from current directory, moves up), 4) Package.json 'main' field. Example resolution: require('mymodule') → looks in ./node_modules/mymodule → ../node_modules/mymodule → / etc. Resolution can be customized using NODE_PATH environment variable or package.json fields.
package.json is a project manifest file containing: 1) Basic info (name, version, description), 2) Dependencies (dependencies, devDependencies), 3) Scripts (start, test, build), 4) Configuration (type, engines). Example: { 'name': 'my-app', 'version': '1.0.0', 'dependencies': { 'express': '^4.17.1' }, 'scripts': { 'start': 'node server.js' }, 'type': 'module' }. It's essential for npm package management and project configuration.
NPM dependency management includes: 1) Installing packages: npm install package-name, 2) Saving dependencies: --save or --save-dev flags, 3) Version control: semantic versioning (^, ~, exact versions), 4) Updating packages: npm update, 5) Auditing security: npm audit. Example managing a project: npm init npm install express --save npm install jest --save-dev npm update npm audit fix
Peer dependencies specify packages that must be installed by the consuming application. Used when: 1) Creating plugins/extensions, 2) Avoiding duplicate dependencies, 3) Ensuring compatibility. Example package.json: { 'name': 'my-plugin', 'peerDependencies': { 'react': '>=16.8.0', 'react-dom': '>=16.8.0' } }. The consuming application must install compatible versions of peer dependencies.
Circular dependencies can be handled through: 1) Restructuring code to avoid cycles, 2) Using dependency injection, 3) Moving shared code to a separate module. Example problem: // a.js const b = require('./b'); // b.js const a = require('./a'); Solution: Create shared module: // shared.js module.exports = { sharedFunction() {} }; Then import shared in both modules.
NPM workspaces enable managing multiple packages in a single repository: 1) Define workspaces in root package.json, 2) Share dependencies across packages, 3) Link local packages together. Example: { 'name': 'monorepo', 'workspaces': ['packages/*'], 'private': true }. Directory structure: /packages/pkg1/package.json /packages/pkg2/package.json. Commands work across all workspaces: npm install --workspace=pkg1
Module loading optimization techniques: 1) Use module caching effectively, 2) Implement lazy loading, 3) Bundle modules for production, 4) Use path aliases. Example lazy loading: const getLodash = () => require('lodash'); function processData(data) { const _ = getLodash(); return _.groupBy(data, 'type'); } Cache example: const cache = {}; function requireFromCache(module) { if (!cache[module]) cache[module] = require(module); return cache[module]; }
Package versioning methods include: 1) Semantic Versioning (MAJOR.MINOR.PATCH), 2) Version ranges (^, ~, *, x), 3) Git URLs, 4) Local paths. Example package.json: { 'dependencies': { 'express': '^4.17.1', // Minor version updates 'lodash': '~4.17.21', // Patch updates only 'mylib': 'file:../mylib', // Local path 'private-pkg': 'git+ssh://git@github.com:org/repo.git' // Git URL } }
Package publishing process: 1) Prepare package.json (name, version, files), 2) Create npm account, 3) npm login, 4) npm publish. Maintenance: 1) Version updates (npm version), 2) README and documentation, 3) Security updates, 4) Deprecation if needed. Example workflow: npm version patch npm publish npm deprecate my-package@"<2.0.0" "Critical security bug fixed in v2.0.0"
package-lock.json ensures consistent installs across environments by: 1) Locking exact versions of dependencies, 2) Recording dependency tree, 3) Including integrity hashes, 4) Maintaining deterministic installs. Example: { 'name': 'project', 'lockfileVersion': 2, 'requires': true, 'packages': { 'node_modules/express': { 'version': '4.17.1', 'resolved': 'https://registry.npmjs.org/express/-/express-4.17.1.tgz', 'integrity': 'sha512-...' } } }
Native modules management includes: 1) node-gyp for compilation, 2) Binary distribution using prebuilt packages, 3) Platform-specific installations. Example package.json: { 'dependencies': { 'bcrypt': '^5.0.1' }, 'scripts': { 'install': 'node-gyp rebuild' } } Installation handling: if (process.platform === 'win32') { module.exports = require('./binary/windows'); } else { module.exports = require('./binary/unix'); }
Security practices include: 1) Regular security audits (npm audit), 2) Version pinning for critical dependencies, 3) Using .npmrc for security settings, 4) Implementing lockfiles, 5) Automated vulnerability scanning. Example: { 'scripts': { 'preinstall': 'npm audit', 'audit-fix': 'npm audit fix' } } .npmrc configuration: audit=true save-exact=true package-lock=true
Module mocking approaches: 1) Jest mock functions, 2) Proxyquire for dependency injection, 3) Manual mocking. Example with Jest: jest.mock('./database', () => ({ query: jest.fn() })); Example with Proxyquire: const proxyquire = require('proxyquire'); const stubs = { './database': { query: () => Promise.resolve([]) } }; const module = proxyquire('./module', stubs);
Module scoping patterns include: 1) IIFE (Immediately Invoked Function Expression), 2) Revealing Module Pattern, 3) ES Modules with private fields, 4) Symbol-based privacy. Example: const createModule = () => { const privateVar = Symbol('private'); return { [privateVar]: 'hidden', publicMethod() { return this[privateVar]; } }; }; ES Module example: export class Module { #privateField = 'hidden'; getPrivate() { return this.#privateField; } }
Environment-specific dependency management: 1) Development vs production dependencies, 2) Optional dependencies, 3) Conditional installations, 4) Environment-specific builds. Example package.json: { 'dependencies': { 'express': '^4.17.1' }, 'devDependencies': { 'jest': '^27.0.0' }, 'optionalDependencies': { 'win-printer': '^1.0.0' }, 'scripts': { 'install': 'node scripts/conditional-install.js' } }
Understand promises, async/await, and callback patterns.
Work with Express.js, REST APIs, and middleware.
Explore clustering, caching, and database optimization.
Expect questions about scalability and microservices.
Join thousands of successful candidates preparing with Stark.ai. Start practicing Node.js questions, mock interviews, and more to secure your dream role.
Start Preparing now