Introducción: ¿por qué es necesario el caching en TypeScript?
Las aplicaciones web modernas requieren alta velocidad de respuesta y una carga mínima en las bases de datos. El caching es una de las formas más efectivas de lograrlo. En el ecosistema de TypeScript (y Node.js), el desarrollador tiene tres enfoques principales: sistemas distribuidos (Redis, Memcached) y soluciones integradas (caché en memoria). En este artículo analizaremos cada uno de ellos, proporcionaremos ejemplos prácticos en TypeScript y ayudaremos a elegir la opción óptima para su proyecto.
El caching permite almacenar datos solicitados con frecuencia en un almacenamiento rápido, evitando operaciones costosas repetitivas (consultas a la BD, cálculos, llamadas a APIs externas). Una estrategia de caching adecuada puede reducir el tiempo de respuesta del servidor entre 10 y 100 veces.
1. Caching integrado en TypeScript (En Memoria)
La forma más sencilla es almacenar datos directamente en la memoria del proceso Node.js. Esto no requiere servicios externos, lo que es ideal para aplicaciones pequeñas o prototipos.
1.1. Uso de Map y WeakMap
Las colecciones integradas de JavaScript son una excelente base para un caché simple. Ejemplo de implementación con TTL (Time To Live):
type CacheEntry<T> = { value: T; expiresAt: number;};
class SimpleCache<T> { private store = new Map<string, CacheEntry<T>>();
set(key: string, value: T, ttlMs: number = 60000): void { this.store.set(key, { value, expiresAt: Date.now() + ttlMs, }); }
get(key: string): T | undefined { const entry = this.store.get(key); if (!entry) return undefined; if (Date.now() > entry.expiresAt) { this.store.delete(key); return undefined; } return entry.value; }
delete(key: string): boolean { return this.store.delete(key); }
clear(): void { this.store.clear(); }}
// Usoconst userCache = new SimpleCache<object>();userCache.set('user:1', { name: 'Alexey' }, 30000); // TTL 30 segconsole.log(userCache.get('user:1'));1.2. Biblioteca node-cache
Para soluciones de producción, es mejor usar la biblioteca probada node-cache. Proporciona capacidades avanzadas: limpieza automática, estadísticas y eventos.
import NodeCache from 'node-cache';
const myCache = new NodeCache({ stdTTL: 100, checkperiod: 120 });
// Guardamos el objetoconst success = myCache.set('myKey', { data: 'value' });if (success) console.log('Caché guardado');
// Leemosconst value = myCache.get('myKey');console.log(value); // { data: 'value' }
// Obtenemos estadísticasconst stats = myCache.getStats();console.log(`Aciertos: ${stats.hits}, Fallos: ${stats.misses}`);Ventajas: simplicidad, latencia de red cero, no requiere instalación de servicios.
Desventajas: el caché se pierde al reiniciar la aplicación, no es adecuado para sistemas distribuidos.
2. Caching con Redis en TypeScript
Redis es la solución de caching más popular en producción. Funciona como un servidor independiente, admite estructuras de datos complejas y es resistente a reinicios de la aplicación.
2.1. Conexión con ioredis
La biblioteca ioredis es el estándar de facto para trabajar con Redis desde TypeScript. Admite clustering, Pub/Sub y Pipeline.
import Redis from 'ioredis';
const redis = new Redis({ host: 'localhost', port: 6379, retryStrategy: (times) => Math.min(times * 50, 2000),});
// Verificación de conexiónredis.on('connect', () => console.log('Conectado a Redis'));redis.on('error', (err) => console.error('Error de Redis:', err));2.2. Ejemplo de caching con TTL
async function getCachedData(key: string): Promise<string | null> { const cached = await redis.get(key); if (cached) { console.log('Datos desde