Node.js
- Backend
- javascript
- Testing
Conceptos Fundamentales de Node.js
Workers y Multithreading
Node.js utiliza un modelo de ejecución single-threaded, pero soporta multithreading mediante el uso de Worker Threads o el Cluster Module para aprovechar múltiples núcleos del procesador.
- Workers
- Permiten ejecutar código JavaScript en hilos separados del main thread.
- Se comunican con el hilo principal mediante ports y mensajes (
postMessage,onmessage).
- Performance
- Aumenta el rendimiento en tareas CPU-bound (procesamiento intensivo, cálculos, compresión).
- No mejora el rendimiento en tareas I/O-bound (lectura de archivos o red).
- Data Transfer
- Se pueden transferir datos entre hilos usando objetos serializados o buffers compartidos.
- Shared Memory
- Con
SharedArrayBuffer, los hilos pueden acceder al mismo bloque de memoria, reduciendo copias innecesarias.
- Con
- Buffer
- Objeto global de Node.js usado para manejar datos binarios. Es esencial para operaciones con streams, archivos, sockets o APIs binarios.
Core Concepts: CORS, Middleware, Request & Response
Node.js con express utiliza middleware para interceptar y procesar peticiones.
- CORS
- Controla el acceso de dominios cruzados.
- Configurable mediante
cors()middleware.
- Middleware
- Funciones que interceptan
req,res, ynext(). - Se pueden usar para autenticación, logging, validación o manejo de errores.
- Funciones que interceptan
- Request & Response
reqcontiene información del cliente, parámetros, body, headers.resmaneja la respuesta (status, json, send, render).
ORM (Object Relational Mapping)
Permite interactuar con bases de datos relacionales usando objetos JS.
- Ejemplo: Sequelize, Prisma.
- Simplifica la escritura de queries SQL, facilita migraciones y modelos de datos.
express 🔥
Ejemplo básico
const express = require('express')
const app = express()
app.get('/', (req, res) => {
res.send('Hello Node.js!')
})
app.listen(3000, () => console.log('Servidor corriendo en puerto 3000'))
`
Cursos y Recursos de Aprendizaje
- JS-nodejs-old
- JS-nodejs-first-app
- nodejs-instalacion en linux
- nodejs-Instalar librerías y borrar node modules
- REST API Design Best Practices Handbook – How to Build a REST API with JavaScript, Node.js, and E…
- Guía definitiva de Node.js- Introducción para desarrolladores - Evolve Academy
- Curso Fundamentos de Node.js - jonmircha - YouTube
- GitHub - jonmircha/youtube-nodejs
-
[API REST con NODE.js GUÍA de BUENAS PRÁCTICAS - YouTube](https://youtu.be/qFmwRriNJWs)
Configuración y Buenas Prácticas
Linter y Formateo
Configuración del Entorno de Node y Express
- How I Set up Production Node.js Project (2024) - YouTube
- GitHub - alexrusin/node-template-2024
- GitHub - alexrusin/node-template-2024 at add-sequelize
GitHub Actions devops
- Workflows para automatizar CI/CD.
- Trigger events: ejecución de acciones (ej. test, deploy).
- Archivos
.ymlpara definir pipelines.
Herramientas y Configuración
- nodemon → recarga automática de servidor en desarrollo.
- Env de
AppDebug→ configurarNODE_ENV,PORT, y variables globales. - Config centralizada
- Crear objeto de configuración que cargue envs solo una vez.
- Usar
process.loadEnvFile()y exportar como constantes.
Tareas Pendientes
- Crear estructura de archivos y entorno de debug.
- Instalar DB con Docker → [hub.docker.com//mysql](https://hub.docker.com//mysql) devops
- Usar Sequelize ORM con TypeScript
Buenas Prácticas en React, JS y Node.js
Variables de entorno
- Usar
process.envde forma eficiente para evitar overhead. - Cargar
.envantes de iniciar el servidor y no en cada función. - Configurar entornos (
development,production,test) en un único archivo de configuración exportado.
Importaciones y Rutas
- Usar rutas relativas limpias con alias
@configurado enjsconfig.jsonotsconfig.json.
React y Asincronía
- Carga dinámica de componentes con
lazy()ySuspense. - Evitar condicionales excesivos (
if) en animaciones usando callbacks (onClose). - Asegurar que las promesas se gestionan correctamente con
Promise.try()enuseEffect.
Optional Chaining
- Operador
?.para evitar errores porundefined. - Optional chaining (.) - JavaScript MDN-Optional_chaining
const userName = user?.profile?.name ?? 'Invitado'
Alternativas a Nodemon
- Usar
whatots-node-devpara un reinicio más rápido y ligero.
Ejemplo: Configuración Base del Proyecto Node.js
# Instalación de dependencias
npm init -y
npm install express cors dotenv nodemon
# Estructura de carpetas
src/
app.js
routes/
controllers/
config/
models/
# Script en package.json
"scripts": {
"dev": "nodemon src/app.js",
"start": "node src/app.js"
}
// src/app.js
import express from 'express'
import cors from 'cors'
import dotenv from 'dotenv'
dotenv.config()
const app = express()
app.use(cors())
app.use(express.json())
app.listen(process.env.PORT || 3000, () =>
console.log(`Servidor en puerto ${process.env.PORT}`)
)
Resumen
Node.js es un entorno eficiente para desarrollar aplicaciones escalables orientadas a eventos. Su integración con express, su ecosistema de herramientas (ORM, ESLint, Prettier, Docker, GitHub Actions) y sus capacidades de paralelización mediante Workers lo convierten en una base sólida tanto para proyectos monolíticos como microservicios modernos.
Node.js – Internals, Rendimiento y Arquitectura Avanzada
- Backend
- node.js
- javascript
- Testing
- devops
Event Loop y Asincronía Avanzada
El Event Loop es el corazón de Node.js. Gestiona la ejecución no bloqueante del código, delegando operaciones a la API del sistema y atendiendo callbacks en diferentes fases.
Fases del Event Loop
- Timers: ejecuta callbacks de
setTimeoutysetInterval. - Pending Callbacks: callbacks de operaciones I/O diferidas.
- Idle & Prepare: tareas internas del sistema.
- Poll: espera eventos nuevos de I/O, ejecuta sus callbacks.
- Check: ejecuta callbacks de
setImmediate. - Close callbacks: cierra sockets o handles (ej.
socket.on('close')).
Microtasks y Macrotasks
- Microtasks: Promesas,
process.nextTick(). - Macrotasks: Timers, I/O,
setImmediate. - Node prioriza siempre las microtasks entre fases del loop.
console.log('start')
setTimeout(() => console.log('timeout'), 0)
setImmediate(() => console.log('immediate'))
process.nextTick(() => console.log('nextTick'))
Promise.resolve().then(() => console.log('promise'))
console.log('end')
`
Streams y Manejo de Datos Masivos
Los Streams permiten procesar datos de forma continua y eficiente, evitando cargar todo en memoria.
Tipos de Streams
- Readable: leen datos (archivos, sockets).
- Writable: escriben datos (archivos, consola).
- Duplex: lectura y escritura (sockets TCP).
- Transform: manipulan datos en tránsito (compresión, cifrado).
Ejemplo: Lectura y Escritura con Streams
import fs from 'fs'
const read = fs.createReadStream('input.txt')
const write = fs.createWriteStream('output.txt')
read.pipe(write)
pipe()conecta streams sin bloquear el event loop.- Ideal para grandes archivos o transferencias HTTP.
Cluster y Procesos Hijos
Cluster
Permite aprovechar múltiples núcleos del sistema para escalar horizontalmente una app Node.js.
import cluster from 'cluster'
import os from 'os'
import http from 'http'
if (cluster.isPrimary) {
const cpus = os.cpus().length
for (let i = 0; i < cpus; i++) cluster.fork()
} else {
http.createServer((req, res) => {
res.end(`Worker ${process.pid}`)
}).listen(3000)
}
- Cada worker ejecuta una copia del servidor.
- El proceso primario maneja balanceo de carga interno.
Procesos Hijos
- Módulo
child_processejecuta scripts o comandos externos. - Ideal para tareas aisladas: backups, cron jobs, CLI tools.
import { exec } from 'child_process'
exec('ls', (err, stdout) => console.log(stdout))
EventEmitter y Eventos Personalizados
El módulo events implementa el patrón Observer interno de Node.js.
import { EventEmitter } from 'events'
const emitter = new EventEmitter()
emitter.on('user:login', user => console.log(`Login: ${user}`))
emitter.emit('user:login', 'admin')
- Base de muchos sistemas de notificación y middleware interno.
- Se puede extender en clases personalizadas.
Manejo de Errores, Logs y Observabilidad
Tipos de errores
- Síncronos: se capturan con
try/catch. - Asíncronos: requieren
Promise.catchoprocess.on('uncaughtException').
Logging estructurado
Usar librerías como Winston o Pino para trazabilidad.
import pino from 'pino'
const logger = pino({ level: 'info' })
logger.info('Server started')
logger.error({ err }, 'Unhandled exception')
Observabilidad
- Integrar métricas con Prometheus, OpenTelemetry, o Grafana.
-
Monitorizar:
- Latencia
- Tiempo de respuesta
- Uso de CPU/RAM
- Ciclos del Event Loop
Seguridad en Node.js
Reglas básicas
- Validar entradas → usar
validatorojoi. - Evitar
eval()oFunction()dinámicos. - Sanitizar input antes de queries SQL o NoSQL.
- Activar helmet para cabeceras seguras en Express.
import helmet from 'helmet'
app.use(helmet())
Rate Limiting
import rateLimit from 'express-rate-limit'
app.use(rateLimit({ windowMs: 60_000, max: 100 }))
Dependencias
- Auditar con
npm auditynpm outdated. - Fijar versiones en
package-lock.jsonopnpm-lock.yaml.
Testing Avanzado
Herramientas
- Jest / Vitest: unit tests.
- Supertest: pruebas HTTP.
- Sinon: mocks, spies, stubs.
import request from 'supertest'
import app from '../src/app.js'
describe('GET /', () => {
it('should return 200', async () => {
await request(app).get('/').expect(200)
})
})
Cobertura
Usar --coverage para medir rutas y módulos no testeados.
Tests de Integración
- Testear flujo real de API (con DB mockeada o Docker).
- Integrar en GitHub Actions devops.
Performance y Profiling
Optimización
- Reusar conexiones DB.
- Evitar loops bloqueantes.
- Usar
Promise.all()para concurrencia.
Profiling
node --inspect app.js
Abrir en Chrome DevTools (chrome://inspect) → analizar CPU, memoria, leaks.
Herramientas de diagnóstico
- clinic.js
- 0x
- node –prof
Distribución y Arquitectura
Patrones comunes
- Microservicios: separación por dominios.
- Message Queue: Redis, RabbitMQ, NATS.
- Workers distribuidos: ejecutar tareas asíncronas.
- CQRS / Event Sourcing: separar lectura y escritura.
Ejemplo: Worker con RabbitMQ
import amqplib from 'amqplib'
const queue = 'tasks'
const connection = await amqplib.connect('amqp://localhost')
const channel = await connection.createChannel()
await channel.assertQueue(queue)
channel.consume(queue, msg => {
console.log('Tarea:', msg.content.toString())
channel.ack(msg)
})
Depuración y CLI de Node.js
Herramientas CLI
node inspect app.js--trace-warnings,--trace-deprecationconsole.table,console.group,console.count
Debugger Visual
- Integración con VSCode usando
.vscode/launch.json. - Breakpoints, variables locales y profiling visual.
Conclusión
Node.js no es solo un entorno de ejecución de JavaScript, sino una plataforma robusta para construir aplicaciones modernas escalables y observables. Comprender su Event Loop, el sistema de Streams, el manejo de procesos, y aplicar prácticas de seguridad, pruebas y profiling permite crear soluciones distribuidas listas para producción.
Node.js – Ecosistema Profesional y Arquitectura en Producción
- Backend
- node.js
- javascript
- devops
- Testing
Gestión de Dependencias y Versionado
npm, pnpm y Yarn
Node.js permite varios gestores de dependencias. Su elección impacta en la velocidad, reproducibilidad y tamaño del proyecto.
- npm
- Predeterminado.
- Usa
package-lock.jsonpara bloqueo de versiones. - Comando útil:
npm ci(instalación limpia, ideal para CI/CD).
- pnpm
- Usa almacenamiento global de dependencias compartidas.
- Ahorra espacio y mejora la velocidad de instalación.
- Comando útil:
pnpm recursive install.
- Yarn
- Foco en rapidez y cacheo.
- Usa
yarn.lockpara versiones deterministas.
nvm (Node Version Manager)
Permite cambiar entre versiones de Node.js sin conflictos.
nvm install 20
nvm use 20
nvm alias default 20
`
- Ideal para mantener compatibilidad entre proyectos o entornos CI.
- Recomendado para flujos devops.
Modularidad y Patrones de Diseño
ESM vs CommonJS
- CommonJS (CJS): usa
require()ymodule.exports. - ESM (ECMAScript Modules): usa
importyexport.
// CJS
const express = require('express')
// ESM
import express from 'express'
- ESM soporta top-level await y tree-shaking.
- En proyectos modernos usar
"type": "module"enpackage.json.
Patrones Relevantes
- Factory Pattern: crear objetos según tipo o contexto.
- Dependency Injection: desacoplar dependencias y facilitar testing.
- Repository Pattern: aislar la lógica de persistencia.
- Clean Architecture: separar capas →
controller,useCase,repository,infra.
// ejemplo de inyección de dependencias
class UserService {
constructor(userRepository) {
this.repo = userRepository
}
async createUser(dto) {
return this.repo.save(dto)
}
}
Node.js con TypeScript
El tipado estático mejora la robustez y mantenibilidad de proyectos grandes.
Configuración
npm install typescript ts-node @types/node --save-dev
npx tsc --init
Tipado básico
interface User {
id: number
name: string
email?: string
}
const getUser = (id: number): Promise<User> => fetchUser(id)
Integración con Express
import express, { Request, Response } from 'express'
const app = express()
app.get('/', (req: Request, res: Response) => res.json({ ok: true }))
- Permite detectar errores antes de ejecutar.
- Se integra fácilmente con ORM tipo Sequelize o Prisma.
Colas de Trabajo y Procesamiento Asíncrono
BullMQ
Framework para procesar tareas en segundo plano sobre Redis.
import { Queue, Worker } from 'bullmq'
const queue = new Queue('emails')
await queue.add('send', { to: 'user@example.com' })
new Worker('emails', job => {
console.log('Enviando a', job.data.to)
})
- Reintentos, prioridades, y gestión de concurrencia.
- Ideal para tareas como notificaciones, pagos, generación de reportes.
Agenda.js
Usa MongoDB para agendar trabajos recurrentes.
import Agenda from 'agenda'
const agenda = new Agenda({ db: { address: 'mongodb://localhost/agenda' } })
agenda.define('say hello', job => console.log('Hello'))
agenda.every('5 minutes', 'say hello')
Worker Threads Coordinados
Ideal para CPU-bound sin bloquear el loop principal.
Escalabilidad y Balanceo
Escalabilidad Vertical
- Aumentar recursos del servidor (CPU/RAM).
- Menos eficiente a largo plazo.
Escalabilidad Horizontal
- Multiplicar instancias usando Cluster o PM2.
pm2 start app.js -i max
pm2 monit
- PM2 maneja reinicios automáticos, logs y métricas.
Cacheo y Optimización
- Usar Redis para cachear peticiones frecuentes.
- Implementar TTL y estrategias LRU.
await redis.setex('user:1', 60, JSON.stringify(user))
- Comprimir respuestas (
compressionmiddleware). - Evitar consultas repetidas en DB.
Integración con APIs y Protocolos Modernos
REST y GraphQL
- REST → rutas predecibles (
/users/:id). - GraphQL → consultas flexibles, ideal para frontends complejos.
import { ApolloServer, gql } from 'apollo-server-express'
const typeDefs = gql`type User { id: ID name: String }`
WebSockets
Para comunicación bidireccional (chat, notificaciones).
import { Server } from 'socket.io'
const io = new Server(3001)
io.on('connection', socket => {
socket.emit('welcome', 'Conectado!')
})
gRPC
Comunicación binaria rápida entre microservicios.
import grpc from '@grpc/grpc-js'
import protoLoader from '@grpc/proto-loader'
Despliegue Profesional y CI/CD
Docker y Contenedores
Dockeriza aplicaciones para asegurar consistencia.
FROM node:20
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
CMD ["node", "src/app.js"]
- Usar docker-compose para servicios DB + API.
- Integrar devops pipelines con GitHub Actions.
CI/CD
Pipeline .yml básico:
name: Node CI
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm test
PM2 y Supervisión
- Clusterización + auto-restart.
- Monitorización con
pm2 monit. - Integración con Keymetrics o Datadog.
Serverless y Edge Functions
Node.js en la Nube
- AWS Lambda, Vercel, Netlify, Cloudflare Workers.
- Ejecución bajo demanda sin servidores persistentes.
Ejemplo AWS Lambda
export const handler = async (event) => {
return {
statusCode: 200,
body: JSON.stringify({ msg: 'Hola desde Lambda!' })
}
}
- Rápido escalado automático.
- Facturación por ejecución.
- Ideal para microservicios pequeños o endpoints event-driven.
Observabilidad y Mantenimiento en Producción
Logs centralizados
- Usar Elastic Stack (ELK) o Grafana Loki.
- Enviar logs de PM2 o Winston vía HTTP o UDP.
Métricas y Health Checks
app.get('/health', (req, res) => res.json({ ok: true, uptime: process.uptime() }))
- Integrar Prometheus client para métricas personalizadas.
- Monitorear tiempos de respuesta y heap usage.
Profiling continuo
- Usar
clinic flameo0xen entorno de staging. - Detectar memory leaks y funciones bloqueantes.
Conclusión
El ecosistema profesional de Node.js va mucho más allá del desarrollo de APIs. Dominar versionado, modularidad, tipado, colas, escalabilidad, seguridad, despliegue y observabilidad permite construir arquitecturas sólidas, eficientes y preparadas para entornos distribuidos o serverless, unificando el ciclo completo de desarrollo Backend → devops → Testing → Producción.
omnivore node js
type: list
name: "Notas con #nodejs en Omnivore"
order:
- property: date_saved
direction: desc
columns:
- file.name
- date_saved
filters:
and:
- file.inFolder("Omnivore")
- file.hasTag("nodejs")
views:
- type: table
name: Table
sort:
- property: file.mtime
direction: DESC
¿Te gusta este contenido? Suscríbete vía RSS