Sign up to our newsletter and receive exclusive discounts and promotions
Following our comprehensive overview of Node.js, let's delve deeper into advanced concepts, architectural patterns, and real-world implementations that make Node.js a powerful choice for modern applications.
Understanding how Node.js manages memory is crucial for building efficient applications:
// Example of memory leak prevention
const cache = new WeakMap(); // Using WeakMap instead of regular Map
function processLargeData(data) {
if (cache.has(data)) {
return cache.get(data);
}
const result = expensiveOperation(data);
cache.set(data, result);
return result;
}
Worker threads enable true parallel execution in Node.js:
const { Worker, isMainThread, parentPort } = require('worker_threads');
if (isMainThread) {
const worker = new Worker(__filename);
worker.on('message', (result) => {
console.log('Calculation result:', result);
});
worker.postMessage({ number: 50 });
} else {
parentPort.on('message', (data) => {
const result = fibonacci(data.number);
parentPort.postMessage(result);
});
}
Implementing resilient services:
class CircuitBreaker {
constructor(requestFn, options = {}) {
this.requestFn = requestFn;
this.state = 'CLOSED';
this.failureCount = 0;
this.failureThreshold = options.failureThreshold || 5;
this.resetTimeout = options.resetTimeout || 60000;
}
async fire(...args) {
if (this.state === 'OPEN') {
throw new Error('Circuit breaker is OPEN');
}
try {
const result = await this.requestFn(...args);
this.failureCount = 0;
return result;
} catch (error) {
this.failureCount++;
if (this.failureCount >= this.failureThreshold) {
this.state = 'OPEN';
setTimeout(() => this.reset(), this.resetTimeout);
}
throw error;
}
}
reset() {
this.failureCount = 0;
this.state = 'CLOSED';
}
}
const http2 = require('http2');
const fs = require('fs');
const server = http2.createSecureServer({
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.crt')
});
server.on('stream', (stream, headers) => {
if (headers[':path'] === '/') {
stream.respond({
'content-type': 'text/html',
':status': 200
});
stream.end('<h1>Hello HTTP/2</h1>');
}
});
class RateLimiter {
constructor(windowMs = 60000, max = 100) {
this.windowMs = windowMs;
this.max = max;
this.clients = new Map();
}
tryRequest(clientId) {
const now = Date.now();
const clientData = this.clients.get(clientId) || { count: 0, windowStart: now };
if (now - clientData.windowStart > this.windowMs) {
clientData.count = 0;
clientData.windowStart = now;
}
if (clientData.count < this.max) {
clientData.count++;
this.clients.set(clientId, clientData);
return true;
}
return false;
}
}
const consul = require('consul')();
const express = require('express');
const app = express();
function registerService() {
consul.agent.service.register({
name: 'user-service',
address: 'localhost',
port: 3000,
check: {
http: 'http://localhost:3000/health',
interval: '10s'
}
}, (err) => {
if (err) throw err;
});
}
class EventBus {
constructor() {
this.subscribers = new Map();
}
subscribe(event, callback) {
if (!this.subscribers.has(event)) {
this.subscribers.set(event, []);
}
this.subscribers.get(event).push(callback);
}
publish(event, data) {
if (this.subscribers.has(event)) {
this.subscribers.get(event).forEach(callback => {
callback(data);
});
}
}
}
describe('User API', () => {
beforeAll(async () => {
await connectDatabase();
});
afterEach(async () => {
await cleanupDatabase();
});
it('should create a new user', async () => {
const response = await request(app)
.post('/api/users')
.send({
username: 'testuser',
email: '[email protected]'
});
expect(response.status).toBe(201);
expect(response.body).toHaveProperty('id');
});
});
class MetricsCollector {
constructor() {
this.metrics = new Map();
this.startTime = Date.now();
}
recordLatency(endpoint, duration) {
if (!this.metrics.has(endpoint)) {
this.metrics.set(endpoint, {
count: 0,
totalDuration: 0,
maxDuration: 0
});
}
const metric = this.metrics.get(endpoint);
metric.count++;
metric.totalDuration += duration;
metric.maxDuration = Math.max(metric.maxDuration, duration);
}
getMetrics() {
const result = {};
this.metrics.forEach((value, key) => {
result[key] = {
avgLatency: value.totalDuration / value.count,
maxLatency: value.maxDuration,
requestCount: value.count
};
});
return result;
}
}
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
# Health check
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:3000/health || exit 1
ENV NODE_ENV=production
CMD ["node", "server.js"]
Node.js continues to evolve, and staying up-to-date with these advanced concepts and patterns is crucial for building robust, scalable applications. The examples and patterns shared here provide a foundation for implementing enterprise-grade Node.js applications.
Remember that performance optimization is an iterative process, and the best practices mentioned here should be adapted to your specific use case and requirements.
What advanced Node.js patterns have you implemented in your projects? Share your experiences and learnings in the comments below.
Back-End Developer