The problem: HTTP doesn't notify
HTTP is request → response: the client asks and the server answers. The server cannot speak first. For a chat that's a problem: if another person writes, how do you find out?
The naive solution is polling: asking every few seconds "is there anything new?".
setInterval(async () => {
const newOnes = await fetch("/messages?since=" + lastId);
// ...
}, 2000);
Polling works, but it's bad for real-time:
- Latency: a message can take up to the full interval to appear.
- Waste: most requests come back empty; each one opens a connection, sends headers, etc.
- Doesn't scale: thousands of clients asking every 2 s saturate the server.
The solution: WebSockets
A WebSocket opens a single persistent, bidirectional connection. After a handshake over HTTP, the channel stays open and either of the two sides can send data whenever it wants, without asking permission again.
| HTTP / polling | WebSocket | |
|---|---|---|
| Direction | client asks | bidirectional |
| Connection | one per request | one persistent |
| Latency | up to the interval | immediate (push) |
| Server initiates? | no | yes |
Socket.io is a widely used library that builds on WebSockets (with fallbacks) and adds reconnection, rooms and named events. In this project the transport (the real WebSocket) is conceptual —it doesn't run in the browser sandbox— but the logic that lives on top (pub/sub, rooms, presence) you are going to implement and validate for real.
Examples
Polling: simple but with latency and waste
let last = 0;
const queue = [{ id: 1, txt: "hi" }]; // simulates the server
function poll() {
const newOnes = queue.filter((m) => m.id > last);
if (newOnes.length) last = newOnes[newOnes.length - 1].id;
console.log("received:", newOnes.length);
}
poll();
poll(); // the second time there's nothing new