1. Pub/sub: el corazón
Por debajo de "enviar un mensaje y que llegue a todos" hay un patrón clásico: publicar / suscribir (pub/sub).
- Los interesados se suscriben dando una función (un callback).
- Cuando alguien publica un mensaje, se llama a todas las funciones suscritas con ese mensaje.
El que publica no sabe quién escucha; solo emite. Eso desacopla emisor y receptores.
const subs = [];
function suscribir(fn) { subs.push(fn); }
function enviar(msg) { subs.forEach((fn) => fn(msg)); }
2. Salas (rooms)
Un chat no es un único canal: tiene salas. Una sala agrupa a las personas
que deben recibir los mismos mensajes ("general", "random", un DM...). En
Socket.io es socket.join("general") y io.to("general").emit(...).
Conceptualmente, una sala es un pub/sub con su propia lista de suscriptores: publicar en "general" solo notifica a quienes están suscritos a "general".
3. Presencia (quién está conectado)
La presencia responde a "¿quién está ahora mismo aquí?". Cuando alguien se
conecta, se añade a la lista; cuando se va (o se cae la conexión), se
quita. Un Set es perfecto: evita duplicados si te reconectas y permite
preguntar "¿está fulano?" en O(1).
const conectados = new Set();
conectados.add("ana"); // entra
conectados.delete("ana"); // sale
[...conectados]; // lista actual
Con estas tres piezas —pub/sub, salas y presencia— tienes el modelo mental completo de un chat en tiempo real. Vamos a construirlas.
Ejemplos
Pub/sub mínimo en acción
const subs = [];
const suscribir = (fn) => subs.push(fn);
const enviar = (m) => subs.forEach((fn) => fn(m));
suscribir((m) => console.log("A recibe:", m));
suscribir((m) => console.log("B recibe:", m));
enviar("hola");