1. How does the JavaScript event loop work? Explain with call stack, microtask queue, and macrotask queue.
Answer: The event loop coordinates the call stack and task queues. Synchronous code runs on the call stack. Asynchronous callbacks are scheduled to either the macrotask queue (setTimeout, setInterval, I/O, setImmediate) or microtask queue (Promises .then(), queueMicrotask). After the current stack empties, the engine runs all microtasks before taking the next macrotask.
// Demo: microtask runs before macrotask
console.log('start');
setTimeout(()=>console.log('macrotask'),0);
Promise.resolve().then(()=>console.log('microtask'));
console.log('end');
// Output: start, end, microtask, macrotask
References: MDN Event Loop, MDN Event Loop
2. Difference between var, let, and const (scope, hoisting, TDZ)?
Answer: var is function-scoped, hoisted with undefined.
let/const are block-scoped, hoisted but in Temporal Dead Zone
until initialization. const cannot be reassigned (but objects are mutable).
// Example
console.log(x); // undefined
var x = 1;
// let y; console.log(y); // ReferenceError if used before initialization
{
let y = 2;
}
3. What is debouncing and throttling? Implement both.
Answer: Debounce: delay execution until calls stop. Throttle: limit execution to once per interval.
// Debounce
function debounce(fn, ms){
let t;
return (...args)=>{ clearTimeout(t); t=setTimeout(()=>fn(...args), ms); };
}
// Throttle
function throttle(fn, ms){
let last = 0;
return (...args)=>{
const now = Date.now();
if(now - last >= ms){ last = now; fn(...args); }
};
}
Reference: Debounce vs Throttle
4. What are closures? Give a practical MERN example.
Answer: A closure is a function retaining access to its lexical scope even when executed outside. Useful for factories, memoization, or encapsulating private state.
// Example: request counter middleware in Express using closure
function requestCounter(){
let count = 0;
return function(req,res,next){
count++;
console.log('requests:', count);
next();
}
}
app.use(requestCounter());
Ref: MDN closures
5. Difference between synchronous and asynchronous JS?
Answer: Synchronous code runs sequentially on the call stack. Asynchronous code offloads tasks (I/O, timers, network) and uses callbacks/promises/async-await to resume execution later without blocking the main thread.
6. Explain prototypal inheritance with an example.
Answer: Objects delegate property lookup to their prototype chain. Use
Object.create or class sugar.
const person = { greet(){ return 'hi'; } };
const alice = Object.create(person);
console.log(alice.greet()); // 'hi'
// ES6 class
class Person{constructor(name){this.name=name}};
class Student extends Person{constructor(n, id){super(n); this.id=id}}
7. Difference between == and ===?
Answer: == does type coercion then compares; ===
is strict equality—no coercion. Prefer === to avoid surprises.
8. process.nextTick() vs microtask queue?
Answer: In Node.js, process.nextTick() queues a callback to
run after the current operation but before other microtasks and I/O. Promises are
microtasks that run in the microtask phase. Use process.nextTick carefully
as it can starve I/O.
9. What are streams in Node.js? Where used?
Answer: Streams are objects for reading/writing continuous data — readable, writable, duplex, transform. Used for files, HTTP, large data processing to avoid buffering whole payloads in memory.
// Pipe a file to response
const fs = require('fs');
app.get('/download', (req,res)=>{
fs.createReadStream('./big.zip').pipe(res);
});
10. Explain middleware in Express with examples.
Answer: Middleware are functions that have access to req,res,next. They can modify request, end response, or call next(). Examples: logging, body parsing, authentication.
// Simple logger
app.use((req,res,next)=>{ console.log(req.method, req.url); next(); });
11. How does Express handle routing internally?
Answer: Express maintains a stack of route and middleware layers. For each request it iterates layers and matches path/method; matched layer executes. Routers are sub-app stacks.
12. Purpose of app.use()?
Answer: Register middleware (global or path-scoped). Order matters — earlier app.use runs first.
13. Error-handling middleware? How to create one?
Answer: Error middleware has 4 args: (err, req, res, next). Put it after routes.
app.use((err, req, res, next)=>{
console.error(err);
res.status(err.status||500).json({error:err.message});
});
14. Node.js clustering — why needed?
Answer: Node is single-threaded per process. Use clustering (cluster module or PM2) to utilize multiple CPU cores by forking worker processes and load-balancing incoming connections.
15. Difference between require and import?
Answer: require() is CommonJS (synchronous).
import is ES Modules (static, can be tree-shaken). Node supports both with
config & extensions (.mjs / package.json "type":"module").
16. Environment variables — why use .env?
Answer: Env vars store config (ports, secrets) separate from code. Use .env for local development (gitignored) and real env vars in production platforms.
17. How to secure APIs in Node.js? (Helmet, rate limiting, CORS)
Answer: Use Helmet to set secure headers, enable CORS carefully, add rate-limiting (express-rate-limit), validate inputs, use HTTPS, sanitize query params, and use JWT with short expiry + refresh tokens.
const helmet = require('helmet');
app.use(helmet());
18. What is async/await? How does it behave in the event loop?
Answer: async functions return Promises. await pauses within the async function; control returns to the event loop and the rest executes as microtasks when awaited Promise resolves. Use try/catch for errors.
19. SQL vs NoSQL?
Answer: SQL: relational, structured schema, strong ACID guarantees. NoSQL (MongoDB): document-based, schema-flexible, horizontally scalable — favors fast development and sharding. Choose based on consistency, transaction needs, joins complexity.
20. What is schema-less architecture in MongoDB?
Answer: Documents can have different shapes (fields) inside same collection. Use Mongoose schemas to enforce structure when needed. Schema-less increases agility but requires careful indexing and validation at app level.
21. Purpose of Mongoose schema and model?
Answer: Schema defines the shape, types, defaults, validation. Model is the compiled constructor for creating and querying documents. Models wrap collection operations with helpful APIs.
const UserSchema = new mongoose.Schema({name:String, email:{type:String, required:true}});
const User = mongoose.model('User', UserSchema);
22. What are MongoDB indexes? Types and use cases.
Answer: Indexes speed queries. Types: single field, compound, text, hashed, TTL. Use for query filters, sort fields, unique constraints; avoid over-indexing (writes cost).
23. Aggregation pipeline — important stages?
Answer: Key stages: $match, $group,
$project, $sort, $limit, $lookup,
$unwind. Pipelines allow powerful transformations server-side.
24. Difference between populate() and $lookup?
Answer: populate() is Mongoose helper that performs extra
query(s) to fetch referenced docs. $lookup is aggregation stage that
performs server-side join between collections. For complex joins and pipelines, prefer
$lookup.
25. How do transactions work in MongoDB?
Answer: Multi-document transactions (on replica sets / sharded clusters) provide ACID semantics using session.startTransaction() and commitTransaction(). Use when multiple docs must change atomically.
26. Sharding vs replication?
Answer: Replication duplicates data across replica set members for high availability. Sharding splits data across shards for horizontal scalability. They can be used together.
27. Mongoose middleware (pre/post hooks)?
Answer: Use schema.pre('save', fn) or schema.post('remove', fn) to run logic before/after operations. Useful for hashing passwords, cascading deletes, audit logs.
28. Designing MongoDB schemas for scalability?
Answer: Model access patterns; embed when one-to-few, reference when one-to-many large. Use proper indexes, avoid large arrays, consider bucketing/time-series, and plan shard keys early.
29. Functional vs class components?
Answer: Functional components are the modern standard (hooks). Class components use lifecycle methods and state via this.setState. Hooks like useState/useEffect replace lifecycle in a cleaner way.
30. How does React Reconciliation work?
Answer: React uses a virtual DOM and performs diffing between render outputs to compute minimal updates. Keys help identify items across renders to preserve identity and minimize DOM operations.
31. What triggers a re-render in React?
Answer: Props change, state change, or parent re-render triggers child re-render. Memoization (React.memo, useMemo, useCallback) helps reduce unnecessary renders.
32. How does useMemo help reduce re-renders? Example.
Answer: useMemo memoizes a computed value across renders when deps unchanged—avoids expensive recalculations.
const expensive = useMemo(()=> heavyCalc(data), [data]);
33. useCallback vs useMemo?
Answer: useCallback memoizes a function reference; useMemo memoizes the result of a computation. useCallback(()=>fn, deps) is shorthand for useMemo(()=>fn, deps).
34. What is useEffect dependency array?
Answer: The deps array controls when effect runs (on mount, when deps change, or never). Empty array = run once on mount. Omitting it runs on every render (and can cause loops).
35. What is React Fiber?
Answer: React Fiber is the reconciliation algorithm rewrite enabling incremental rendering, priorities, and better scheduling of rendering work (interruptible renders).
36. What is prop drilling and how to avoid it?
Answer: Prop drilling is passing props through intermediate components. Avoid via Context API, Redux, Zustand, or lift state to nearest common ancestor or use hooks.
37. Controlled vs uncontrolled components?
Answer: Controlled: component state controls form inputs (value from state). Uncontrolled: rely on DOM refs to read values. Controlled favored for validation and predictable state.
38. Lazy loading and code splitting?
Answer: Use React.lazy + Suspense or dynamic import() to split bundles and load code on demand. Helps initial load performance.
const Other = React.lazy(()=> import('./Other'));
Loading... 39. What is hydration in React?
Answer: Hydration attaches React event listeners to server-rendered HTML so client can take over without re-rendering entire DOM. ReactDOM.hydrate used for SSR outputs.
40. Why do we need keys in lists?
Answer: Keys provide stable identity to list items so React can match elements across renders to minimize DOM updates. Use unique stable ids, not indexes for reordered lists.
41. How does Redux work internally? store, reducer, actions?
Answer: Store holds state and exposes dispatch/getState. Reducers are pure functions computing new state from actions. Middleware intercepts actions to add async behavior (thunk/saga).
42. Redux vs Context API?
Answer: Context provides scoped dependency injection of values; Redux provides a structured global store with devtools, middleware, time-travel, and predictable update patterns. Use Redux for complex shared state and middleware needs.
43. Middleware in Redux? (Thunk / Saga)
Answer: Middleware wraps dispatch to handle async. Thunk lets actions return functions (dispatch inside). Saga uses generator functions to orchestrate side-effects with better testability for complex flows.
44. How does Zustand differ from Redux? When to use each?
Answer: Zustand is lightweight, no boilerplate, uses hooks-based store. Redux is more structured with devtools and middleware. Use Zustand for simpler local/global state, Redux for large apps requiring strict patterns.
45. Explain JWT internals (header, payload, signature).
Answer: JWT = base64Url(header).base64Url(payload).signature. Header declares alg/type. Payload holds claims (sub, exp). Signature (HMAC/RSA) verifies integrity. Never store secrets in payload; it's not encrypted by default.
46. What is stateless authentication?
Answer: Server does not keep session info; token (JWT) contains necessary user data and is validated per request. Easier to scale but revocation handling requires strategies (blacklist, short expiry, refresh tokens).
47. Why store refresh token in HTTP-only cookie?
Answer: HTTP-only cookies are inaccessible to JS, reducing XSS risk. Store refresh tokens there and rotate them. Use SameSite & Secure flags to reduce CSRF risk.
48. Difference between authorization and authentication?
Answer: Authentication proves identity (login). Authorization decides what an authenticated identity can do (roles, permissions).
49. How to prevent XSS and CSRF?
Answer: XSS: sanitize/escape output, use Content-Security-Policy, avoid innerHTML. CSRF: use SameSite cookies, CSRF tokens for state-changing POST, or store tokens in local storage + double submit pattern (note XSS tradeoffs).
50. Why not store JWT in localStorage?
Answer: localStorage is accessible via JS, vulnerable to XSS-based token theft. Prefer HTTP-only cookies for refresh tokens and short-lived access tokens in memory or secure storage strategies.
51. How does password hashing work? (bcrypt salt rounds)
Answer: Hashing converts password to fixed-length digest. bcrypt adds salt and adjustable rounds to increase compute cost, slowing brute-force attacks. Use a strong work factor (e.g., 10-12) and pepper if needed.
52. REST API constraints?
Answer: REST constraints include client-server, statelessness, cacheable responses, uniform interface, layered system, code-on-demand (optional). Following REST aids scalability and simplicity.
53. PUT vs PATCH?
Answer: PUT replaces the entire resource (idempotent). PATCH applies partial updates (may or may not be idempotent depending on implementation).
54. What is idempotency in APIs?
Answer: An operation is idempotent if repeating it has same effect as once. GET/PUT/DELETE are expected idempotent; POST usually not. Important for retries and safe network operations.
55. Pagination — implement in MongoDB?
Answer: Use skip/limit for simple cases. For large datasets prefer range-based (cursor) pagination using a sort key (e.g., _id or createdAt) for better performance.
// Range pagination
const docs = await collection.find({createdAt: {$lt: lastSeen}}).sort({createdAt:-1}).limit(pageSize);
56. What is rate limiting? How to implement in Express?
Answer: Rate limiting prevents abuse (throttles requests per IP). Use express-rate-limit, or reverse-proxy-level limits (NGINX, Cloudflare) and consider distributed stores (Redis) for multi-instance apps.
57. How does WebSocket differ from HTTP?
Answer: HTTP is request/response (stateless). WebSocket establishes a persistent full-duplex TCP connection allowing server push and low latency two-way messaging. Socket.IO builds on WebSocket and adds fallbacks, events, and rooms.
58. Socket.IO rooms and namespaces?
Answer: Namespaces isolate logic under different endpoints. Rooms are arbitrary channels within a namespace to broadcast to subsets of clients. Use rooms for private chats, groups.
59. Implement private chats using rooms?
Answer: Create a room per chat (e.g., user ids combined). Join both participants to room and emit messages to that room. Authenticate socket connection using token middleware.
60. Polling fallback in Socket.IO?
Answer: Socket.IO can start with long-polling then upgrade to WebSocket if supported. This fallback ensures compatibility with older clients or proxies blocking WebSocket.
61. What is Docker? Why use it?
Answer: Docker containers package apps with dependencies into portable images. Benefits: consistent environments, easier CI/CD, isolation, faster deployments, and resource efficiency compared to VMs.
62. What is a Dockerfile? Important commands?
Answer: Dockerfile describes image build. Key commands: FROM, RUN, COPY, ADD, WORKDIR, ENV, EXPOSE, CMD, ENTRYPOINT. Keep layers small and cache-friendly.
# Example Node Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
63. Image vs container?
Answer: Image is a read-only template; container is a running instance of an image with writable layer. You run containers from images.
64. Best practices for Dockerizing a MERN app?
Answer: Multi-stage builds, small base images (alpine), environment variables, healthchecks, separate containers per service, use .dockerignore, avoid storing secrets in images, prefer docker-compose or k8s for orchestration.
65. How to run Node.js with PM2 in production?
Answer: Use PM2 to manage processes, restarts, clustering, and monitoring.
Example: pm2 start server.js -i max --name my-app. Use pm2 ecosystem file
for config and startup scripts.
66. What is CI/CD? GitHub Actions example?
Answer: CI/CD automates build/test/deploy. GitHub Actions uses workflows (.yml) triggered on push. Example: build test and deploy to Docker Hub or cloud provider on push to main.
67. What is Webpack? loaders and plugins?
Answer: Webpack bundles modules. Loaders transform file types (babel-loader, css-loader). Plugins extend capabilities (HtmlWebpackPlugin). Vite is faster dev server alternative using native ESM.
68. Difference between Vite and CRA?
Answer: Vite uses native ESM and a fast dev server with on-demand compilation; CRA uses webpack dev server and full bundling. Vite offers faster cold starts and HMR.
69. Bundling, minification, tree-shaking?
Answer: Bundling concatenates modules into bundles. Minification reduces size by removing whitespace/shortening names. Tree-shaking removes unused exports from final bundles.
70. Design a chat application (WhatsApp-like)?
Answer: Use React client, Socket.IO backend, Node + clustering, MongoDB for message store with appropriate indexes, Redis for session/store and pub/sub, file storage (S3), and consider horizontal scaling with load balancer. Handle presence, delivery receipts, and backpressure.
71. Design scalable authentication system?
Answer: Use stateless access tokens, short expiry, refresh tokens stored in http-only cookies, central auth service (OAuth/JWT), rotate and revoke tokens with a blacklist in Redis when necessary, MFA support, and distributed rate limiting.
72. Design feed system (pagination, infinite scroll)?
Answer: Use cursor-based pagination, prefetch next pages, cache hot feeds (Redis), denormalize feed entries, and use background jobs to generate personalized feeds.
73. Design a notification system?
Answer: Store notifications, use push services (FCM, APNs), websocket channels for realtime, batch delivery via worker queues, and user preferences for channels and throttling.
74. What is caching? Tools (Redis, CDN)?
Answer: Cache reduces latency by storing computed responses. Use CDN for static assets, Redis for in-memory caching of DB queries, and HTTP caching headers for browser caching.
75. How to optimize MongoDB queries?
Answer: Use appropriate indexes, avoid unbounded skip, project only required fields, analyze with explain(), and denormalize when read-heavy with accepted write complexity.
76. What is load balancing?
Answer: Distributing incoming traffic across multiple backend instances to improve reliability and capacity. Use round-robin, least-connections, or health-checked algorithms via NGINX, HAProxy, or cloud LB.
77. What is compression? Use compression() in Express?
Answer: Compression (gzip, brotli) reduces payload size and improves
transfer time. Use express compression middleware:
const compression = require('compression'); app.use(compression());
78. What is Jest?
Answer: Jest is a JS testing framework with assertions, mocks, snapshot testing, and built-in runner. Works well for unit and integration tests in Node & React.
79. Integration testing vs unit testing?
Answer: Unit tests test isolated units (functions/components). Integration tests validate multiple modules working together (DB, API routes). Both are important; E2E tests simulate user flows.
80. How do you test an Express API?
Answer: Use supertest with Jest/Mocha to spin up app and make requests. Mock DB or use test database, seed data, and teardown between tests.
const request = require('supertest');
const app = require('../app');
describe('GET /users', ()=>{
it('returns 200', async ()=>{
await request(app).get('/users').expect(200);
});
});