DevPath · Learn to code ESPTEN

Project: real-time chat

Pub/sub, rooms and presence

1. Pub/sub: the heart

Underneath "send a message and have it reach everyone" there's a classic pattern: publish / subscribe (pub/sub).

The publisher doesn't know who is listening; it just emits. That decouples the sender and the receivers.

const subs = [];
function subscribe(fn) { subs.push(fn); }
function send(msg) { subs.forEach((fn) => fn(msg)); }

2. Rooms

A chat isn't a single channel: it has rooms. A room groups the people that should receive the same messages ("general", "random", a DM...). In Socket.io it's socket.join("general") and io.to("general").emit(...).

Conceptually, a room is a pub/sub with its own list of subscribers: publishing to "general" only notifies those who are subscribed to "general".

3. Presence (who is connected)

Presence answers "who is here right now?". When someone connects, they're added to the list; when they leave (or the connection drops), they're removed. A Set is perfect: it avoids duplicates if you reconnect and lets you ask "is so-and-so here?" in O(1).

const connected = new Set();
connected.add("ana");   // enters
connected.delete("ana"); // leaves
[...connected];          // current list

With these three pieces —pub/sub, rooms and presence— you have the complete mental model of a real-time chat. Let's build them.

Examples

Minimal pub/sub in action

const subs = [];
const subscribe = (fn) => subs.push(fn);
const send = (m) => subs.forEach((fn) => fn(m));
subscribe((m) => console.log("A receives:", m));
subscribe((m) => console.log("B receives:", m));
send("hi");
Put this into practice

DevPath is a hands-on course: you read the theory here; in the app you put it into practice with exercises that really run, offline.

Start free in the app →
← Why real-time? WebSockets vs HTTPView the module →