HTML Server-Sent Events (SSE)
Previously, Web Workers ran JavaScript in a background thread and talked to the page with postMessage — local CPU work, no server stream. This lesson leaves off-thread compute and introduces Server-Sent Events (SSE): the server pushes a stream of text updates to the browser over HTTP. Your HTML page still loads a script; that script opens EventSource, listens for message, and paints the DOM when e.data arrives. Scope stays practical — open, listen, one-way push — not Node stream servers, Django Channels products, or a full realtime architecture course.
Why SSE in an HTML course
Beginners need live scores, logs, or status lines without inventing a custom socket protocol. SSE is the common first browser API for “server pushes text over HTTP.” After Web Workers’ “page and worker message locally,” this lesson’s split is different: the server owns the stream; the page script owns EventSource and the DOM. You need new EventSource(url), onmessage / onerror, and the idea that the response is text/event-stream — enough for intro pages without building a chat backend or a WebSocket fleet.
Direct answer
1) Create const es = new EventSource("/events") (use a real stream URL when you have a backend).
2) Handle es.onmessage (or addEventListener("message", …)) and read e.data.
3) Update the DOM on the page when events arrive.
4) Handle es.onerror for disconnect / retry awareness.
5) SSE is one-way: server → browser. Browser→server needs a normal request or a different tool.
6) Prefer WebSockets when you need full duplex chat-style messaging; prefer polling when updates are rare; prefer Workers when the work is local CPU, not a server stream.
📊 SSE vs WebSocket vs Worker
| Topic | SSE (this lesson) | WebSocket | Web Worker (prev) |
|---|---|---|---|
| Typical role | Server→browser text stream | Full duplex messages | Local off-thread compute |
| Browser entry | EventSource(url) | new WebSocket(url) | new Worker(url or Blob) |
| Direction | One-way (server push) | Two-way | Page ↔ worker (no server required) |
| Transport idea | HTTP text/event-stream | WS protocol | postMessage / onmessage |
| DOM updates | On the page script | On the page script | On the page script only |
| This course depth | Required (browser pattern) | Contrast only | Previous lesson |
| Not this lesson | Full backend stream servers | Chat product design | SharedWorker fleets |
Tiny EventSource listen pattern
This snippet shows the browser side only. /events must be a real SSE endpoint on your host; without a server the connection errors — that still teaches the API shape.
<pre id="out">Waiting for stream…</pre>
<script>
const out = document.getElementById("out");
const es = new EventSource("/events");
es.onmessage = function (e) {
out.textContent = "Last update: " + e.data;
};
es.onerror = function () {
out.textContent = "SSE error or closed (need a real /events stream)";
};
</script>
Reading the listen calls
new EventSource("/events")opens a long-lived HTTP stream to that pathonmessageruns when the server sends a defaultmessageevente.dataholds the text payload for that event- The page writes into
<pre>— same DOM ownership rule as Workers, different source of data - Unlike Web Workers, nothing uses
postMessageto a background thread — this is server push - Without a compatible server,
onerroris expected in local demos - Keep intros tiny: one URL, one handler, one DOM write
Append stream lines to a log
Live UIs often append each event instead of replacing one line. This demo keeps the last few lines in a list when messages arrive.
<ul id="log"></ul>
<script>
const log = document.getElementById("log");
const es = new EventSource("/events");
es.onmessage = function (e) {
const li = document.createElement("li");
li.textContent = e.data;
log.appendChild(li);
while (log.children.length > 5) {
log.removeChild(log.firstChild);
}
};
es.onerror = function () {
if (!log.dataset.noted) {
log.dataset.noted = "1";
const li = document.createElement("li");
li.textContent = "Stream not available — wire a text/event-stream URL";
log.appendChild(li);
}
};
</script>
Reading the log idea
- Each
onmessagecreates a new<li>frome.data - Cap the list so demos stay readable
- Still one-way: the page does not
postMessageback through EventSource - Still not a Web Worker — no Blob worker, no off-thread sum loop
- Named events (
addEventListener("ping", …)) exist in the API; defaultmessageis enough for intro - Call
es.close()when you no longer need the stream - Next optional lesson: XHTML history and polyglot markup — a different HTML-course topic
Choosing SSE, polling, sockets, or workers
- Server pushes frequent status/log lines over HTTP: good intro SSE fit
- Rare refresh every few minutes: simple polling may be enough
- Chat that must send both ways continuously: consider WebSockets
- Heavy local loop that freezes scrolling: that was Web Workers, not SSE
- Drag a card into a dashed zone: that was Drag and Drop
- Building the Node/Django stream endpoint itself: beyond this HTML browser intro
Practice — open, listen, contrast
- Read the EventSource listen snippet; note
onmessageandonerror. - Skim what a
text/event-streamresponse looks like in trusted docs (data:lines). - Read the append-log snippet; explain why the page updates the DOM, not the server.
- Write one sentence: Web Workers compute locally off-thread; SSE receives server-pushed events.
- Write one sentence: SSE is one-way; WebSockets are the usual full-duplex alternative.
- (Optional) Point EventSource at a real tutorial SSE URL when you have a backend.
- Peek ahead: XHTML covers stricter XML-style markup history — not live streams.
Easy mistakes
- Expecting EventSource to send browser→server payloads like a WebSocket
- Confusing SSE with Web Workers (server stream ≠ background CPU thread)
- Forgetting the server must speak a compatible event-stream format / content type
- Using SSE for updates so rare that a single fetch would do
- Ignoring
onerrorso silent failures look like a “broken” page - Treating this intro as a full backend streaming or WebSocket product course
- Mixing up
EventSourcewithWorkerorWebSocketconstructors
Summary
- SSE streams server→browser text updates over HTTP
- Use
EventSource, handleonmessage/onerror, paint the DOM on the page - One-way push; WebSockets when you need full duplex
- Web Workers were local off-thread compute; this lesson is server push
- Real demos need a
text/event-streamURL; the browser pattern still matters alone - Next: HTML XHTML for XML-style document history in the course
🧠 Test Your Knowledge
Test Your Knowledge
Challenge yourself with this interactive quiz and see how well you understand the topic
📝 Instructions
- Read each question carefully
- Select the best answer for each question
- You can retake the quiz as many times as you want
- Your progress will be shown at the top