Title: Nodejs Runtime — LearnCoachAssist

Q: What is Node.js?
A: Node.js is a JavaScript runtime built on Chrome's V8 engine. It allows running JavaScript outside the browser, using an event-driven, non-blocking I/O model that makes it lightweight and efficient for building scalable network applications.

Q: What is the Node.js event loop?
A: The event loop is the mechanism that allows Node.js to perform non-blocking I/O operations despite JavaScript being single-threaded. It continuously checks the call stack and callback queue, executing callbacks when the stack is empty. Phases include: timers → pending callbacks → idle/prepare → poll → check → close callbacks.

Q: What are the phases of the Node.js event loop?
A: - Timers – executes setTimeout and setInterval callbacks
- Pending callbacks – I/O callbacks deferred to next iteration
- Poll – retrieves new I/O events
- Check – executes setImmediate callbacks
- Close callbacks – e.g. socket.on('close')

Q: What is the difference between setImmediate() and setTimeout()?
A: setImmediate() executes in the check phase of the event loop, after the poll phase completes. setTimeout(fn, 0) executes in the timers phase on the next iteration. When called within an I/O callback, setImmediate() always fires before setTimeout().

Q: What is process.nextTick() and how does it differ from setImmediate()?
A: process.nextTick() fires immediately after the current operation, before the event loop continues. It is processed on the microtask queue, not part of any event loop phase. setImmediate() fires on the next iteration of the event loop. Overusing nextTick can starve I/O.

Q: What are Streams in Node.js?
A: Streams are objects that let you read or write data continuously in chunks rather than loading everything into memory. There are four types:
- Readable – e.g. fs.createReadStream()
- Writable – e.g. fs.createWriteStream()
- Duplex – both readable and writable (e.g. TCP socket)
- Transform – modifies data as it passes through (e.g. zlib.createGzip())

Q: How do you pipe streams in Node.js?
A: Use the .pipe() method to connect a readable stream to a writable stream:
const fs = require('fs');
fs.createReadStream('input.txt')
  .pipe(fs.createWriteStream('output.txt'));
The modern alternative is pipeline() from stream/promises, which handles errors automatically.

Q: What is backpressure in Node.js streams?
A: Backpressure occurs when a writable stream cannot consume data as fast as a readable stream produces it. Node.js handles this by returning false from writable.write(), signaling the readable stream to pause. The 'drain' event on the writable stream indicates it's ready for more data.

Q: What is the CommonJS module system?
A: CommonJS is Node.js's original module system. Modules are loaded synchronously using require() and exported using module.exports or exports:
const fs = require('fs');
module.exports = { myFunc };
Each file is treated as a separate module with its own scope.

Q: What is the ES Modules (ESM) system in Node.js?
A: ESM is the official JavaScript module standard, supported in Node.js 12+. Uses import/export syntax:
import fs from 'fs';
export function myFunc() {}
Enable via "type": "module" in package.json or use .mjs file extension. ESM is asynchronous and supports top-level await.

Q: What are the key differences between CommonJS and ESM?
A: - Loading: CommonJS is synchronous; ESM is asynchronous
- Syntax: require/module.exports vs import/export
- Scope: CommonJS wraps in a function; ESM has strict mode by default
- Top-level await: Only ESM supports it
- Caching: Both cache modules, but ESM uses live bindings

Q: What is Express.js middleware?
A: Middleware functions are functions that have access to the request object (req), response object (res), and the next function (next). They can:
- Execute code
- Modify req and res
- End the request-response cycle
- Call next() to pass control to the next middleware

Q: What is the order of middleware execution in Express?
A: Middleware executes in the order it is defined with app.use() or route methods. The flow is top-down. If a middleware does not call next(), the request hangs. Error-handling middleware has four parameters: (err, req, res, next) and should be defined last.

Q: What are the types of Express middleware?
A: - Application-level – bound to app using app.use()
- Router-level – bound to express.Router()
- Error-handling – has 4 params: (err, req, res, next)
- Built-in – express.json(), express.static(), express.urlencoded()
- Third-party – e.g. cors, helmet, morgan

Q: How do you create a basic Express REST API?
A: const express = require('express');
const app = express();
app.use(express.json());
app.get('/api/users', (req, res) => {
  res.json([{ id: 1, name: 'Alice' }]);
});
app.post('/api/users', (req, res) => {
  res.status(201).json(req.body);
});
app.listen(3000);

Q: What are Express route parameters and query strings?
A: Route params are defined with a colon: app.get('/users/:id', ...) and accessed via req.params.id.
Query strings come after ? in the URL: /users?role=admin and are accessed via req.query.role. Route params identify resources; query strings filter or modify the response.

Q: What are Promises in Node.js?
A: A Promise represents the eventual completion or failure of an asynchronous operation. It has three states:
- Pending – initial state
- Fulfilled – operation completed successfully
- Rejected – operation failed
Use .then() for success, .catch() for errors, and .finally() for cleanup.

Q: What is async/await in Node.js?
A: async/await is syntactic sugar over Promises that makes asynchronous code look synchronous:
async function fetchData() {
  try {
    const data = await getFromDB();
    return data;
  } catch (err) {
    console.error(err);
  }
}
An async function always returns a Promise. await pauses execution until the Promise resolves.

Q: What is Promise.all() and when would you use it?
A: Promise.all() takes an array of Promises and resolves when all of them resolve, or rejects if any one rejects:
const [users, posts] = await Promise.all([
  fetchUsers(),
  fetchPosts()
]);
Use it to run independent async operations concurrently for better performance.

Q: What is the difference between Promise.all(), Promise.allSettled(), and Promise.race()?
A: - Promise.all() – resolves when all fulfill; rejects on first rejection
- Promise.allSettled() – waits for all to settle (fulfill or reject); never short-circuits
- Promise.race() – resolves/rejects as soon as the first Promise settles
- Promise.any() – resolves on first fulfillment; rejects only if all reject

Q: What is a Buffer in Node.js?
A: A Buffer is a fixed-size chunk of memory allocated outside the V8 heap, used to handle binary data directly. Common uses include reading files, network protocols, and image processing:
const buf = Buffer.from('Hello');
console.log(buf.toString('utf8')); // Hello
console.log(buf.length); // 5

Q: How do you create and manipulate Buffers?
A: - Buffer.alloc(10) – creates a zero-filled buffer of 10 bytes
- Buffer.from('text') – creates from a string
- Buffer.from([1, 2, 3]) – creates from an array
- buf.toString('utf8') – converts to string
- buf.slice(0, 5) – returns a sub-buffer
- Buffer.concat([buf1, buf2]) – merges buffers

Q: How do you read a file in Node.js?
A: Asynchronous (recommended):
const fs = require('fs/promises');
const data = await fs.readFile('file.txt', 'utf8');
Synchronous:
const data = fs.readFileSync('file.txt', 'utf8');
Streaming (for large files):
const stream = fs.createReadStream('file.txt');
stream.on('data', chunk => console.log(chunk));

Q: How do you write a file in Node.js?
A: Write entire file:
await fs.writeFile('out.txt', 'content', 'utf8');
Append to file:
await fs.appendFile('log.txt', 'new line\\n');
Streaming write:
const ws = fs.createWriteStream('out.txt');
ws.write('chunk1');
ws.end('done');
Always handle errors with try/catch or .catch().

Q: What are the key fs module methods?
A: - fs.readFile() / fs.writeFile() – read/write files
- fs.mkdir() / fs.rmdir() – create/remove directories
- fs.readdir() – list directory contents
- fs.stat() – get file metadata
- fs.unlink() – delete a file
- fs.rename() – rename/move a file
- fs.watch() – watch for file changes
Use fs/promises for async/await support.

Q: What is the path module in Node.js?
A: The path module provides utilities for working with file and directory paths:
- path.join('dir', 'file.txt') – joins path segments
- path.resolve('./file') – resolves to absolute path
- path.basename('/a/b/c.txt') – returns 'c.txt'
- path.extname('file.js') – returns '.js'
- path.dirname('/a/b/c') – returns '/a/b'

Q: What is the child_process module?
A: The child_process module allows Node.js to spawn subprocesses. Key methods:
- exec(cmd) – runs a shell command, buffers output
- execFile(file) – runs an executable directly
- spawn(cmd) – launches a process with streaming I/O
- fork(module) – spawns a new Node.js process with IPC channel

Q: What is the difference between exec() and spawn()?
A: - exec() buffers the entire output in memory and returns it in a callback. Best for short-lived commands with small output.
- spawn() returns output as a stream, making it suitable for long-running processes or large output.
exec runs in a shell by default; spawn does not unless { shell: true } is specified.

Q: What is the cluster module in Node.js?
A: The cluster module allows you to create multiple worker processes that share the same server port, utilizing all CPU cores:
const cluster = require('cluster');
if (cluster.isPrimary) {
  for (let i = 0; i < os.cpus().length; i++)
    cluster.fork();
} else {
  app.listen(3000);
}
The OS distributes connections across workers via round-robin.

Q: How does Node.js handle errors?
A: Node.js uses multiple error-handling patterns:
- try/catch – for synchronous and async/await code
- Error-first callbacks – callback(err, result)
- .catch() – for Promises
- EventEmitter 'error' – for stream/event errors
- process.on('uncaughtException') – last resort for unhandled errors
- process.on('unhandledRejection') – catches unhandled Promise rejections

Q: What is the error-first callback pattern?
A: The error-first callback pattern is a Node.js convention where the first argument of a callback is an error object (or null if no error):
fs.readFile('file.txt', (err, data) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log(data);
});
Always check err before using the result.

Q: How do you handle uncaught exceptions in Node.js?
A: Use process.on('uncaughtException') to catch synchronous errors and process.on('unhandledRejection') for unhandled Promises:
process.on('uncaughtException', (err) => {
  console.error('Uncaught:', err);
  process.exit(1);
});
Best practice: log the error, clean up resources, and exit. Do not attempt to continue running after an uncaught exception.

Q: What is npm?
A: npm (Node Package Manager) is the default package manager for Node.js. It provides:
- A CLI tool for installing, updating, and managing packages
- A registry (npmjs.com) hosting over 2 million packages
- Key commands: npm install, npm update, npm run, npm init, npm publish

Q: What is the purpose of package.json?
A: package.json is the manifest file for a Node.js project. It contains:
- name and version – project identity
- scripts – custom commands (npm run dev)
- dependencies – production packages
- devDependencies – development-only packages
- main / module – entry points
- engines – required Node.js version

Q: What is the difference between dependencies and devDependencies?
A: dependencies are packages required to run the application in production (installed with npm install).
devDependencies are only needed during development and testing (e.g. test frameworks, linters). Installed with npm install --save-dev. In production, run npm install --production to skip devDependencies.

Q: What is package-lock.json?
A: package-lock.json is an auto-generated file that locks the exact versions of every installed dependency and sub-dependency. It ensures:
- Reproducible builds across different machines
- Deterministic installs – same dependency tree every time
- Security – prevents unexpected version changes
Always commit it to version control.

Q: What is semantic versioning (semver) in npm?
A: Semver uses the format MAJOR.MINOR.PATCH:
- MAJOR (1.x.x) – breaking changes
- MINOR (x.1.x) – new features, backward compatible
- PATCH (x.x.1) – bug fixes, backward compatible
Prefixes: ^1.2.3 allows minor + patch updates; ~1.2.3 allows only patch updates; 1.2.3 pins exact version.

Q: How do you use environment variables in Node.js?
A: Access environment variables via process.env:
const port = process.env.PORT || 3000;
const dbUrl = process.env.DATABASE_URL;
Set them via:
- Shell: PORT=3000 node app.js
- .env file with dotenv: require('dotenv').config();
- System environment configuration
Never commit secrets to source code.

Q: What is the dotenv package?
A: dotenv loads environment variables from a .env file into process.env:
// .env file
DB_HOST=localhost
DB_PORT=5432
// app.js
require('dotenv').config();
console.log(process.env.DB_HOST);
Add .env to .gitignore to keep secrets out of version control. Use .env.example as a template.

Q: What is the EventEmitter class in Node.js?
A: EventEmitter is the core of Node.js's event-driven architecture:
const { EventEmitter } = require('events');
const emitter = new EventEmitter();
emitter.on('data', (msg) => console.log(msg));
emitter.emit('data', 'Hello!');
Key methods: on(), once(), emit(), removeListener(). Many Node.js core modules inherit from EventEmitter.

Q: What is the http module in Node.js?
A: The built-in http module creates HTTP servers and makes HTTP requests without external dependencies:
const http = require('http');
const server = http.createServer((req, res) => {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World');
});
server.listen(3000);
Express.js is built on top of this module.

Q: What are HTTP status codes used in REST APIs?
A: - 200 – OK (successful GET/PUT)
- 201 – Created (successful POST)
- 204 – No Content (successful DELETE)
- 400 – Bad Request (invalid input)
- 401 – Unauthorized (not authenticated)
- 403 – Forbidden (not authorized)
- 404 – Not Found
- 500 – Internal Server Error

Q: What is RESTful API design?
A: REST (Representational State Transfer) principles:
- Use HTTP methods: GET (read), POST (create), PUT (update), DELETE (remove)
- Use nouns for endpoints: /api/users not /api/getUsers
- Return proper status codes
- Be stateless – each request contains all needed info
- Support filtering/pagination: ?page=2&limit=10

Q: How do you handle CORS in Express?
A: CORS (Cross-Origin Resource Sharing) is handled using the cors middleware:
const cors = require('cors');
app.use(cors()); // allow all origins
// Or configure specific origins:
app.use(cors({
  origin: 'https://example.com',
  methods: ['GET', 'POST'],
  credentials: true
}));
Without CORS, browsers block cross-origin requests.

Q: What is the util.promisify() function?
A: util.promisify() converts a callback-based function into one that returns a Promise:
const util = require('util');
const fs = require('fs');
const readFile = util.promisify(fs.readFile);
const data = await readFile('file.txt', 'utf8');
This allows using older callback APIs with modern async/await syntax. Node.js now also provides fs/promises natively.

Q: What is the global object in Node.js?
A: In Node.js, the global object is global (equivalent to window in browsers). Key globals include:
- __dirname – current directory path (CommonJS only)
- __filename – current file path (CommonJS only)
- process – current process info
- console – logging utilities
- Buffer – binary data handling
- setTimeout, setInterval

Q: What is the process object in Node.js?
A: process is a global object providing info about the current Node.js process:
- process.env – environment variables
- process.argv – command-line arguments
- process.cwd() – current working directory
- process.pid – process ID
- process.exit(code) – exit the process
- process.memoryUsage() – memory stats
- process.on('signal') – handle OS signals

Q: What is middleware chaining in Express?
A: Multiple middleware functions can be applied to a single route:
const auth = (req, res, next) => {
  if (!req.headers.token) return res.status(401).end();
  next();
};
const log = (req, res, next) => {
  console.log(req.method, req.url);
  next();
};
app.get('/api/data', auth, log, handler);
Each middleware must call next() to continue the chain.

Q: How do you validate request data in Express?
A: Use validation libraries like express-validator or Joi:
const { body, validationResult } = require('express-validator');
app.post('/users',
  body('email').isEmail(),
  body('name').notEmpty(),
  (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty())
      return res.status(400).json({ errors: errors.array() });
});

Q: What is the Worker Threads module?
A: worker_threads enables true parallel execution of JavaScript using threads (unlike cluster which uses processes):
const { Worker } = require('worker_threads');
const worker = new Worker('./heavy-task.js');
worker.on('message', result => console.log(result));
worker.postMessage(data);
Ideal for CPU-intensive tasks like image processing or data parsing without blocking the event loop.