Patterns from Node.js Ecosystem
Node.js, Redux, and XState demonstrate event-driven and state management patterns at scale.
| Pattern | Project | Where | What It Does |
|---|---|---|---|
| Observer / Pub-Sub | Node.js | lib/events.js | EventEmitter — foundation of Node's event-driven architecture |
| Observer / Pub-Sub | Redux | createStore.ts | subscribe() + dispatch() — state change notification |
| State Machine | XState | StateMachine.ts | Industry-standard finite state machine library |
| Backpressure | Node.js | writable.js | writeOrBuffer() — highWaterMark + drain event flow control |
| Iterator / Lazy Eval | Node.js | lib/internal/streams/ | Async iterators for streams — for await (const chunk of stream) |
| Retry Backoff | Node.js | dns, http | DNS resolution retry with exponential backoff |
| Dependency Graph | pnpm | graph-sequencer | Topological sort of workspace packages for build order |
| Rate Limiter | Express | express-rate-limit | Token bucket middleware for API rate limiting |
| Circuit Breaker | opossum | lib/circuit.js | Node.js circuit breaker for microservice resilience |
| Event Loop | Node.js (libuv) | deps/uv/src/unix/core.c | uv_run() — single-threaded I/O multiplexing via epoll/kqueue |
| Middleware Chain | Koa.js | koa-compose | Compose middleware into an onion-model pipeline with async/await |
How They Compose: An HTTP Request
When an Express/Koa server handles a request, patterns compose from the network layer through to the response:
Incoming HTTP request▼libuv's uv_run() picks up the socket event from epoll/kqueue. The request is dispatched to the JS callback on the main thread. No threads blocked.
express-rate-limit checks the token bucket. If the client exceeded their quota, respond 429 immediately.
Koa-compose runs middleware in onion order: auth → validate → handler → log. Each calls next() to proceed or short-circuits on error.
The handler emits events (e.g., 'userCreated'). EventEmitter notifies all subscribers: cache invalidation, audit log, notification service — all decoupled.
If the response streams a large file, the Writable stream applies highWaterMark. When the client reads slowly, the 'drain' event pauses the producer to prevent memory blowup.
The event loop is the foundation: everything runs on a single thread, and I/O never blocks. This is why Node.js can handle thousands of concurrent connections — each request uses patterns (middleware, observers, backpressure) rather than spawning threads.