Which Real‑Time Data Technique Is Best? Polling, WebSocket, or SSE Compared

This article compares three real‑time data update methods—short and long polling, WebSocket, and Server‑Sent Events—explaining their principles, advantages, drawbacks, and providing practical code examples so developers can choose the most suitable solution for their web applications.

大转转FE
大转转FE
大转转FE
Which Real‑Time Data Technique Is Best? Polling, WebSocket, or SSE Compared

Introduction

Modern web applications demand real‑time interaction such as instant messaging, live dashboards, and push notifications. Developers can meet these requirements using three main techniques: polling, WebSocket, and Server‑Sent Events (SSE). The article evaluates each method and suggests scenarios where they excel.

1. Polling

1.1 Short Polling

Short polling repeatedly sends HTTP requests at a fixed short interval regardless of whether new data is available. It is easy to understand, implement, and works in any environment that supports HTTP. However, each request incurs the full TCP handshake (three‑way handshake, four‑way termination), leading to unnecessary resource consumption and latency when data updates are infrequent.

1.2 Long Polling

Long polling keeps the HTTP request open until the server has new data or a timeout occurs. This reduces the number of empty requests and improves real‑time responsiveness, but the server must hold the connection in memory, which can exhaust resources under heavy load. It also still suffers from latency if the timeout is too long.

Both short and long polling are sub‑optimal for strict real‑time requirements because they either generate many useless requests or keep connections idle for long periods.

2. WebSocket

WebSocket establishes a single TCP connection that upgrades from HTTP, enabling full‑duplex communication. After a handshake (client sends Upgrade: websocket and Connection: Upgrade headers, server responds with status 101 and matching headers), both sides can push data at any time without the request‑response limitation.

2.1 Handshake Phase

Client sends an HTTP request with Upgrade: websocket and Connection: Upgrade headers.

Server, if it supports WebSocket, replies with status 101 and includes Sec-WebSocket-Accept for security verification.

2.2 Data Transfer Phase

After the handshake, the connection remains open, allowing the client to send messages and the server to push updates instantly.

2.3 Connection Maintenance and Closure

Both sides use heartbeat frames to detect broken connections.

Either side can close the connection by sending a close frame, after which resources are released.

2.4 Example

Client (Vue.js) creates a WebSocket connection to ws://localhost:3000, handles open, message, and close events, and sends messages via socket.send().

<div id="app">
  <input v-model="message" placeholder="Enter message" />
  <button @click="sendMessage">Send</button>
  <h3>Received messages:</h3>
  <ul>
    <li v-for="(msg, index) in receivedMessages" :key="msg">{{ msg }}</li>
  </ul>
</div>
<script>
  const app = new Vue({
    el: "#app",
    data() { return { message: "", receivedMessages: [], socket: null }; },
    mounted() {
      this.socket = new WebSocket("ws://localhost:3000");
      this.socket.addEventListener("open", () => console.log("Connected"));
      this.socket.addEventListener("message", event => {
        this.receivedMessages.push(event.data);
      });
      this.socket.addEventListener("close", () => console.log("Closed"));
    },
    methods: {
      sendMessage() {
        if (this.socket.readyState === WebSocket.OPEN) {
          this.socket.send(this.message);
          this.message = "";
        } else {
          console.log("Socket not ready");
        }
      }
    }
  });
</script>

Server (Node.js with the ws library) accepts connections, echoes received messages, and broadcasts a timestamp to all clients every second.

const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 3000 });
const clients = [];
wss.on('connection', ws => {
  console.log('Client connected');
  clients.push(ws);
  ws.on('message', message => {
    console.log(`Received: ${message}`);
    ws.send(`You sent: ${message}`);
  });
  ws.on('close', () => {
    console.log('Client disconnected');
    const i = clients.indexOf(ws);
    if (i > -1) clients.splice(i, 1);
  });
});
setInterval(() => {
  const msg = `Server time: ${new Date().toLocaleString()}`;
  clients.forEach(c => { if (c.readyState === WebSocket.OPEN) c.send(msg); });
}, 1000);
console.log('WebSocket server listening on port 3000');

3. Server‑Sent Events (SSE)

SSE uses a single HTTP connection to push events from server to client. It is unidirectional, based on the HTTP protocol, and works with the EventSource API in browsers.

3.1 Client Request

The client sends a normal HTTP request to an endpoint (e.g., /events) with headers Content-Type: text/event-stream, Cache-Control: no-cache, and Connection: keep-alive. The server keeps the connection open and streams data.

3.2 Server Response

The server writes lines prefixed with data: followed by two line breaks ( \n\n) for each event, maintaining the connection indefinitely or until an error occurs.

3.3 Client Reception

In JavaScript, an EventSource object receives messages via its onmessage handler, parsing JSON or plain text as needed.

3.4 Closing the Stream

The connection ends when the client calls close() or the server encounters an error and terminates the stream.

3.5 Example

Server (Express) creates an /events endpoint that sets the required headers and sends a JSON payload every three seconds.

const express = require('express');
const app = express();
const port = 3000;
app.get('/events', (req, res) => {
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');
  const interval = setInterval(() => {
    const data = `data: { "time": "${new Date().toLocaleString()}" }

`;
    res.write(data);
  }, 3000);
  req.on('close', () => clearInterval(interval));
});
app.listen(port, () => console.log(`Server running at http://localhost:${port}`));

Client code creates an EventSource pointing to the endpoint and updates the UI on each message.

mounted() {
  const source = new EventSource('http://localhost:3000/events');
  source.onmessage = event => {
    const data = JSON.parse(event.data);
    this.message = data.time;
  };
  source.onerror = err => console.log('SSE error:', err);
}

Comparison and Conclusion

Polling is simple but inefficient for high‑frequency updates. Long polling improves latency but still ties up server resources. WebSocket offers full‑duplex, low‑latency communication suitable for interactive applications such as chat or gaming. SSE provides a lightweight, server‑to‑client stream ideal for one‑way updates like live feeds, with lower server overhead but limited to text data and unidirectional flow.

Developers should select the technique that matches their use case: use short polling for infrequent checks, long polling when occasional updates are acceptable, WebSocket for bidirectional real‑time interaction, and SSE for simple server‑push scenarios.

backendfrontendreal-timeWebSocketWeb developmentPollingSSE
大转转FE
Written by

大转转FE

Regularly sharing the team's thoughts and insights on frontend development

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.