Is WebSocket Still the Best Choice for Real‑Time Push? A Comparison with SSE and Polling
The article compares three server‑to‑client push techniques—polling, WebSocket, and Server‑Sent Events (SSE)—detailing their mechanisms, advantages, drawbacks, browser compatibility, and suitable use cases, and provides step‑by‑step Node/Express demos showing how to implement SSE in a simple web page.
Introduction
In many web applications the server needs to push data to the client in real time—e.g., dashboards, unread‑message centers, chat.
Server‑to‑Client Push Options
Polling
WebSocket
Server‑Sent Events (SSE)
Polling
Polling creates the illusion of push by repeatedly sending HTTP requests from the client. It consumes a new HTTP connection for each request, occupies a browser’s limited concurrent connection slots, and cannot deliver data instantly.
Drawbacks:
Each request incurs the full TCP handshake/teardown overhead.
Client must keep sending requests for the entire page lifetime, which is unfriendly.
Browsers limit concurrent connections per host (e.g., Chrome caps at 6), and a long‑running poll occupies one slot.
Long‑interval polls may miss timely updates.
WebSocket
WebSocket is a full‑duplex protocol that allows bidirectional communication between client and server. It is powerful but introduces a new ws/wss protocol that not all browsers support, making it heavier than SSE.
Compatibility: lower than SSE; some older browsers lack support.
Server‑Sent Events (SSE)
SSE is a unidirectional, long‑living HTTP/1.1 connection where the server can continuously push text/event‑stream data to the client. It uses the existing HTTP infrastructure, so most servers support it out of the box.
Advantages:
Lightweight protocol, lower client overhead than WebSocket.
Runs over standard HTTP/HTTPS, no extra server support needed.
Built‑in reconnection handling.
Customizable data types.
Limitation: Internet Explorer does not support SSE; mini‑programs also lack support.
Comparison Summary (official)
WebSocket is full‑duplex; SSE is one‑way (server‑to‑client).
WebSocket requires server‑side support for the ws protocol; SSE works on any HTTP server.
SSE is simpler and lighter; WebSocket is more complex.
SSE automatically reconnects on disconnection; WebSocket needs extra handling.
SSE allows custom data formats.
Typical Use Cases
SSE is ideal for scenarios where only the server pushes data, such as real‑time dashboards or notification centers.
WebSocket fits cases that need bidirectional interaction, the classic example being chat applications.
SSE API Overview
Creating a connection: var source = new EventSource(url); Connection readyState values:
0 – EventSource.CONNECTING (not yet open or reconnecting)
1 – EventSource.OPEN (open and receiving data)
2 – EventSource.CLOSED (closed, no reconnection)
Key events: open – fired when the connection is established. message – fired when a data chunk arrives. error – fired on communication errors such as a broken connection.
Typical response headers:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-aliveDemo: Implementing an SSE Link
Frontend (plain HTML/JavaScript):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SSE Demo</title>
</head>
<body>
<ul id="ul"></ul>
<script>
function createLi(data){ let li=document.createElement("li"); li.innerHTML=String(data.message); return li; }
let source = '';
if (window.EventSource) {
source = new EventSource('http://localhost:8088/sse/');
} else {
throw new Error("Browser does not support SSE");
}
source.onopen = function(){ console.log("Connection opened"); };
source.onmessage = function(event){
const data = JSON.parse(event.data);
console.log(data);
document.getElementById("ul").appendChild(createLi(data));
};
source.onerror = function(){ console.log("Connection error"); };
</script>
</body>
</html>Backend (Node.js + Express):
const express = require('express');
const app = express();
const port = 8088;
app.all("*", (req, res, next) => {
res.header("Access-Control-Allow-Origin", '*');
res.header("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("Access-Control-Allow-Credentials", true);
if (req.method === 'OPTIONS') {
res.sendStatus(200);
} else {
next();
}
});
app.get("/sse", (req, res) => {
res.set({
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
console.log("SSE connection opened");
setInterval(() => {
const data = { message: `Current time is ${new Date().toLocaleTimeString()}` };
res.write(`data: ${JSON.stringify(data)}
`);
}, 1000);
});
app.listen(port, () => console.log(`Server running at http://localhost:${port}`));Running the two files and opening the HTML page displays a continuously updating list of timestamps, demonstrating a working SSE stream.
Conclusion
SSE is lighter than WebSocket.
SSE runs over HTTP/HTTPS, requiring no extra server protocol.
WebSocket introduces a new ws/wss protocol.
Use SSE when only the server pushes data.
Choose WebSocket for bidirectional communication such as chat.
Both have good browser compatibility except IE (no SSE) and some mini‑program environments.
Polling is the least efficient option and should be avoided unless absolutely necessary.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architect's Guide
Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
