Backend Development 12 min read

Choosing Between Polling, Server‑Sent Events, and WebSockets for Real‑Time Web Applications

This article compares three real‑time communication techniques—long/short polling, WebSockets, and Server‑Sent Events—by explaining their mechanisms, presenting client‑ and server‑side code examples, and discussing their advantages, drawbacks, and suitable use‑cases to help developers select the appropriate method for a dashboard application.

Architects Research Society
Architects Research Society
Architects Research Society
Choosing Between Polling, Server‑Sent Events, and WebSockets for Real‑Time Web Applications

Building real‑time web applications requires sending data from server to client, which can be achieved via client‑initiated polling or server‑initiated push.

The three common approaches are:

Long/short polling (client pull)

WebSockets (server push)

Server‑Sent Events (SSE) (server push)

Example use‑case: a dashboard that streams activity feeds from GitHub, Twitter, etc., needing a suitable method.

1. Polling

Polling periodically requests updates; short polling uses fixed intervals, long polling keeps the request open until data is available. Example client‑side long‑polling code:

/* Client - subscribing to the github events */
subscribe: (callback) => {
  const pollUserEvents = () => {
    $.ajax({
      method: 'GET',
      url: 'http://localhost:8080/githubEvents',
      success: (data) => {
        callback(data) // process the data
      },
      complete: () => {
        pollUserEvents();
      },
      timeout: 30000
    })
  }
  pollUserEvents()
}

Drawbacks include multiple TCP round‑trips, lack of multiplexing, and timeout issues.

2. WebSockets

WebSocket provides a persistent full‑duplex TCP connection. The handshake upgrades an HTTP request to WebSocket. Simple client implementation:

$(function () {
  window.WebSocket = window.WebSocket || window.MozWebSocket;
  const connection = new WebSocket('ws://localhost:8080/githubEvents');
  connection.onopen = function () { /* connection opened */ };
  connection.onerror = function (error) { /* handle error */ };
  connection.onmessage = function (message) {
    try {
      const githubEvent = JSON.parse(message.data);
    } catch (e) {
      console.log('This doesn\'t look like a valid JSON: ' + message.data);
      return;
    }
    // handle incoming message
  };
});

Node.js server side using express‑ws:

const express = require('express');
const events = require('./events');
const path = require('path');
const app = express();
const port = process.env.PORT || 5001;
const expressWs = require('express-ws')(app);
app.get('/', (req, res) => {
  res.sendFile(path.join(__dirname + '/static/index.html'));
});
app.ws('/', (ws, req) => {
  const githubEvent = {}; // sample event
  ws.send('message', githubEvent);
});
app.listen(port, () => {
  console.log('Listening on', port);
});

WebSockets require handling many HTTP‑level concerns manually and do not benefit from HTTP/2 multiplexing.

3. Server‑Sent Events (SSE)

SSE uses a single HTTP connection where the server pushes events to the client via the EventSource API. Simple client code:

const evtSource = new EventSource('/events');
evtSource.addEventListener('event', function(evt) {
  const data = JSON.parse(evt.data);
  // Use data here
}, false);

Node.js server implementation:

// events.js
const EventEmitter = require('eventemitter3');
const emitter = new EventEmitter();
function subscribe(req, res) {
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    Connection: 'keep-alive'
  });
  const heartbeat = setInterval(() => res.write('\n'), 15000);
  const onEvent = (data) => {
    res.write('retry: 500\n');
    res.write(`event: event\n`);
    res.write(`data: ${JSON.stringify(data)}\n\n`);
  };
  emitter.on('event', onEvent);
  req.on('close', () => {
    clearInterval(heartbeat);
    emitter.removeListener('event', onEvent);
  });
}
function publish(eventData) {
  emitter.emit('event', eventData);
}
module.exports = { subscribe, publish };

// App.js
const express = require('express');
const events = require('./events');
const app = express();
const port = process.env.PORT || 5001;
app.get('/events', cors(), events.subscribe);
app.listen(port, () => {
  console.log('Listening on', port);
});

SSE offers simpler implementation, automatic HTTP/2 multiplexing, and a single connection per client, making it a strong choice for many real‑time dashboards, though it is limited to unidirectional server‑to‑client streams and may not suit high‑frequency bidirectional scenarios like MMO games.

In summary, after evaluating the trade‑offs, SSE often emerges as the most efficient solution for typical dashboard use‑cases, while WebSockets are preferable when full duplex communication is required.

Backendfrontendreal-timeServer-Sent EventsPollingWebSockets
Architects Research Society
Written by

Architects Research Society

A daily treasure trove for architects, expanding your view and depth. We share enterprise, business, application, data, technology, and security architecture, discuss frameworks, planning, governance, standards, and implementation, and explore emerging styles such as microservices, event‑driven, micro‑frontend, big data, data warehousing, IoT, and AI architecture.

0 followers
Reader feedback

How this landed with the community

login 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.