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.
  • 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, y next().
    • Se pueden usar para autenticación, logging, validación o manejo de errores.
  • Request & Response
    • req contiene información del cliente, parámetros, body, headers.
    • res maneja 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

GitHub Actions devops

  • Workflows para automatizar CI/CD.
  • Trigger events: ejecución de acciones (ej. test, deploy).
  • Archivos .yml para definir pipelines.

Herramientas y Configuración

  • nodemon → recarga automática de servidor en desarrollo.
  • Env de AppDebug → configurar NODE_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.env de forma eficiente para evitar overhead.
  • Cargar .env antes 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 en jsconfig.json o tsconfig.json.

React y Asincronía

  • Carga dinámica de componentes con lazy() y Suspense.
  • Evitar condicionales excesivos (if) en animaciones usando callbacks (onClose).
  • Asegurar que las promesas se gestionan correctamente con Promise.try() en useEffect.

Optional Chaining

  • Operador ?. para evitar errores por undefined.
  • Optional chaining (.) - JavaScript MDN-Optional_chaining
const userName = user?.profile?.name ?? 'Invitado'

Alternativas a Nodemon

  • Usar what o ts-node-dev para 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

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

  1. Timers: ejecuta callbacks de setTimeout y setInterval.
  2. Pending Callbacks: callbacks de operaciones I/O diferidas.
  3. Idle & Prepare: tareas internas del sistema.
  4. Poll: espera eventos nuevos de I/O, ejecuta sus callbacks.
  5. Check: ejecuta callbacks de setImmediate.
  6. 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_process ejecuta 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.catch o process.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 validator o joi.
  • Evitar eval() o Function() 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 audit y npm outdated.
  • Fijar versiones en package-lock.json o pnpm-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-deprecation
  • console.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

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.json para 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.lock para 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() y module.exports.
  • ESM (ECMAScript Modules): usa import y export.
// CJS
const express = require('express')

// ESM
import express from 'express'
  • ESM soporta top-level await y tree-shaking.
  • En proyectos modernos usar "type": "module" en package.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 (compression middleware).
  • 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 flame o 0x en 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 BackenddevopsTesting → 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