Introdução: por que o cache é necessário em TypeScript?
Aplicações web modernas exigem alta velocidade de resposta e carga mínima nos bancos de dados. O cache é uma das maneiras mais eficazes de conseguir isso. No ecossistema TypeScript (e Node.js), o desenvolvedor tem três abordagens principais: sistemas distribuídos (Redis, Memcached) e soluções integradas (cache in-memory). Neste artigo, analisaremos cada uma delas, forneceremos exemplos práticos em TypeScript e ajudaremos você a escolher a melhor opção para seu projeto.
O cache permite armazenar dados frequentemente solicitados em um armazenamento rápido, evitando operações caras repetidas (consultas ao banco de dados, cálculos, chamadas a APIs externas). Uma estratégia de cache adequada pode reduzir o tempo de resposta do servidor em 10 a 100 vezes.
1. Cache integrado em TypeScript (In-Memory)
A maneira mais simples é armazenar dados diretamente na memória do processo Node.js. Isso não requer serviços externos, sendo ideal para aplicações pequenas ou protótipos.
1.1. Uso de Map e WeakMap
As coleções nativas do JavaScript são uma excelente base para um cache simples. Exemplo de implementação com 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 soluções de produção, é melhor usar a biblioteca testada node-cache. Ela oferece recursos avançados: limpeza automática, estatísticas e eventos.
import NodeCache from 'node-cache';
const myCache = new NodeCache({ stdTTL: 100, checkperiod: 120 });
// Salva o objetoconst success = myCache.set('myKey', { data: 'value' });if (success) console.log('Cache salvo');
// Lêconst value = myCache.get('myKey');console.log(value); // { data: 'value' }
// Obtém estatísticasconst stats = myCache.getStats();console.log(`Acertos: ${stats.hits}, Erros: ${stats.misses}`);Vantagens: simplicidade, latência de rede zero, não requer instalação de serviços.
Desvantagens: o cache é perdido ao reiniciar a aplicação, não é adequado para sistemas distribuídos.
2. Cache com Redis em TypeScript
Redis é a solução de cache mais popular em produção. Ele funciona como um servidor separado, suporta estruturas de dados complexas e é resiliente a reinicializações da aplicação.
2.1. Conexão com ioredis
A biblioteca ioredis é o padrão de fato para trabalhar com Redis a partir do TypeScript. Ela suporta clusterização, Pub/Sub e Pipeline.
import Redis from 'ioredis';
const redis = new Redis({ host: 'localhost', port: 6379, retryStrategy: (times) => Math.min(times * 50, 2000),});
// Verificação de conexãoredis.on('connect', () => console.log('Conectado ao Redis'));redis.on('error', (err) => console.error('Erro no Redis:', err));2.2. Exemplo de cache com TTL
async function getCachedData(key: string): Promise<string | null> { const cached = await redis.get(key); if (cached) { console.log('Dados do