Web Development

Node.js and Express

In 2009, Ryan Dahl presented Node.js with a provocative thesis: Apache holds one thread per connection - that is wasteful. With 10,000 simultaneous connections, Apache spawns 10,000 threads. Node.js uses a single thread with an event loop. LinkedIn switched from Rails to Node.js and cut their server count from 30 to 3 at the same load. Non-blocking I/O changed the way the industry thinks about web server performance.

  • **Netflix:** switched to Node.js for server-side rendering; page load time dropped by 70% and memory usage by 40%
  • **PayPal:** rewrote a Java service in Node.js; twice as many requests per second, 35% faster response time, and the team shipped twice as much code
  • **Express vs Fastify:** Express holds around 70% of the Node.js server market; Fastify is 2-3x faster through optimized routing and JSON serialization

Event Loop and Async I/O

Node.js handles thousands of simultaneous connections in a single thread. This sounds like a limitation, but in practice it is an architectural advantage for I/O-intensive workloads. The secret: Event Loop plus non-blocking I/O. While Node.js waits for a database response, it processes other requests. The one cardinal sin: CPU-intensive operations on the main thread - they block the entire event loop.

Event loop phases: timers (setTimeout/setInterval) -> pending callbacks -> idle/prepare -> poll (I/O) -> check (setImmediate) -> close callbacks. The microtask queue (Promise.then, queueMicrotask) drains between each phase. process.nextTick runs before the microtask queue. libuv - the underlying library, manages a thread pool for file I/O, crypto, and DNS.

A Node.js server responds with a 2-3 second delay on all requests and CPU is at 100%. The database is fine. What is the most likely cause?

Express Middleware Pipeline

Express middleware is a pipeline of functions, each receiving request, response, and next. Order matters: middleware executes in registration order. This is not obvious but critical: if auth middleware is registered after the route handler, it will never run for that route. The middleware pattern allows building applications from reusable, testable building blocks.

Middleware types: Application-level (app.use), Router-level (router.use), Error-handling (4 params: err, req, res, next), Built-in (express.json, express.static), Third-party (cors, helmet, morgan). next() with no arguments goes to the next middleware. next(err) goes to the error handler. next('route') skips remaining middleware for the current route.

An Express middleware calls next(new Error('DB timeout')). What happens?

Express Router and Application Structure

An Express Router is a mini-application: a separate namespace for middleware and routes. Instead of one file with a thousand lines, routers allow organizing code by domain. Proper routing structure is not just aesthetics: it enables testability (a router can be tested independently), reuse (one router for multiple API versions), and security (middleware applied precisely to the right paths).

Express Router: router.get, router.post, router.use, router.param. app.use('/api/v1', router) - mounting. router.route('/users').get(handler).post(handler) - method chaining for one path. express.Router({ strict: true }) - strict mode (distinguishes /users from /users/). mergeParams: true - access parent router params in nested routers.

app.get('/users', handler1) and app.get('/users', handler2) are registered in sequence. handler1 calls res.json(). What happens to handler2?

Error Handling in Express

An unhandled error in production means a 500 response with a full stack trace sent to the client. A centralized error handler in Express is the single place that decides how to respond to errors. The right strategy: classify errors (operational vs programming), log with context, respond safely (without leaking internal details). Async errors in Express 4 need a wrapper or try/catch + next(err); Express 5 catches them automatically.

Express error handler: 4 parameters (err, req, res, next) - exactly four are required. Operational errors (4xx) vs programming errors (5xx): the former are expected (not found, validation), the latter are bugs. process.on('unhandledRejection') and process.on('uncaughtException') - last resort, usually trigger a process restart. async-express wrapper or express-async-errors - for clean async error handling in Express 4.

Node.js is unsuitable for CPU-intensive tasks, so it cannot be used for image or video processing

Node.js is unsuitable for CPU-intensive tasks on the main thread; Worker Threads and child_process solve this

Node.js Worker Threads (since v10.5) let you run CPU-intensive code in separate threads without blocking the event loop. Sharp (image processing) and ffmpeg wrappers use this approach. The issue is not with Node.js itself but with incorrect architectural usage.

An Express error handler is registered first, before all routes. Will it work?

Key Ideas

  • **Event Loop** - single thread, non-blocking I/O; CPU-intensive operations on the main thread block all requests; Worker Threads are the solution
  • **Middleware pipeline** - registration order is critical; next() continues the chain, next(err) goes to the error handler, res.send() terminates the request
  • **Router** - a mini-application for organizing code by domain; allows applying middleware with surgical precision
  • **Centralized error handler** - last middleware with 4 parameters; separates operational errors from programming errors

Related Topics

Node.js and Express are the foundation for more specialized frameworks:

  • REST API Design — Express provides the tools for implementing REST; API design determines the routing structure
  • NestJS — NestJS is built on top of Express/Fastify and adds DI, decorators, and modular architecture

Вопросы для размышления

  • Node.js uses a single thread - how does this affect horizontal scaling? When do you use the cluster module vs PM2 vs multiple Docker containers?
  • The Express middleware chain is an implementation of the Chain of Responsibility pattern. Which other GoF patterns does Express middleware implement?
  • When is it worth migrating from Express to Fastify or Hono? What factors drive this decision?

Связанные уроки

  • net-21-http-basics
Node.js and Express

0

1

Sign In