Server‑Sent Events (SSE) vs WebSocket vs Polling: Concepts, Comparison, and Implementation Demo
This article explains the three common server‑to‑client push techniques—polling, WebSocket, and Server‑Sent Events—detailing their principles, advantages, drawbacks, appropriate use‑cases, and provides complete front‑end and Node‑Express back‑end demo code to help developers choose and implement the right solution.
In modern web development, scenarios such as real‑time dashboards, unread message notifications, and chat features often require the server to push data to the client. The article introduces three typical solutions: polling, WebSocket, and Server‑Sent Events (SSE), and compares their characteristics.
Polling is a pseudo‑push technique where the client repeatedly sends HTTP requests to the server. Its disadvantages include high request overhead, long‑lasting connections that consume browser concurrency limits, and delayed data delivery.
WebSocket provides a full‑duplex communication channel over a new ws/wss protocol. It enables bidirectional messaging, making it suitable for chat applications, but requires server support for the protocol and is comparatively heavier.
SSE is a lightweight, unidirectional protocol built on standard HTTP/HTTPS. It offers lower client overhead, automatic reconnection, and is supported by most browsers except older IE versions. SSE is ideal when only the server needs to push data.
The article lists the main differences:
WebSocket is full‑duplex; SSE is server‑to‑client only.
WebSocket needs server‑side support for ws/wss; SSE works over existing HTTP servers.
SSE is simpler and lighter; WebSocket is more complex.
SSE includes built‑in reconnection; WebSocket requires custom handling.
SSE allows custom data types.
Typical business scenarios:
SSE: real‑time dashboards, message center notifications—situations where only the server pushes data.
WebSocket: chat or any feature requiring bidirectional communication.
SSE API Overview
Creating a connection: var source = new EventSource(url);
Connection readyState values:
0 – CONNECTING (connection not yet established or broken)
1 – OPEN (connection established, data can be received)
2 – CLOSED (connection closed, no reconnection)
Key events:
open – triggered when the connection opens.
message – triggered when data arrives.
error – triggered on communication errors.
Data format (HTTP headers):
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-aliveDemo Implementation
Front‑end (HTML + JavaScript) demo:
<!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>Document</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("当前浏览器不支持SSE");
}
source.onopen = function(event) {
console.log(source.readyState);
console.log("长连接打开");
};
source.onmessage = function(event) {
console.log(JSON.parse(event.data));
console.log("收到长连接信息");
let li = createLi(JSON.parse(event.data));
document.getElementById("ul").appendChild(li);
};
source.onerror = function(event) {
console.log(source.readyState);
console.log("长连接中断");
};
</script>
</html>Back‑end (Node.js + Express) demo:
const express = require('express');
const app = express();
const port = 8088;
app.all("*", function(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("进入到长连接了");
setInterval(() => {
const data = { message: `Current time is ${new Date().toLocaleTimeString()}` };
res.write(`data: ${JSON.stringify(data)}\n\n`);
}, 1000);
});
app.listen(port, () => {
console.log(`项目启动成功-http://localhost:${port}`);
});Running the two files launches a simple SSE server that streams the current time to the browser, which displays each message as a list item.
Conclusion
SSE is lighter than WebSocket and works over standard HTTP.
WebSocket offers full‑duplex communication for scenarios like chat.
Polling is the least efficient and should be avoided unless no other method is supported.
IE does not support SSE; mini‑programs also lack SSE support.
Architect
Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.
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.