Web Sockets vs Server-Sent Events vs Long Polling
Alex | Last updated: April 15, 2024
Modern web applications are expected to be real-time. So far as I know, there are three mainstream client-server communication methods that allow for as close to real-time as we can get at the moment:
Long Polling
Long polling is a hackish solution to simulate real-time client-server communication.
Its most hackish ancestor, just traditional “polling,” involved consistent server fetches over constant intervals. A basic implementation might look something like this:
function poll() {
fetch('some_url_goes_here')
.then((response) => {
console.log('Data:' response.data);
// Do something with response.data
})
.catch((error) => {
console.error(error);
// Handle error
})
}
setInterval(poll, 5000); // Execute poll every 5 seconds
As you can imagine, this approach to “real-time” means plenty of unnecessary server calls and quite a bit of overhead.
Long polling improves upon this method by emulating server push communication via a persistent server connection —instead of repeatedly requesting data at regular intervals—that stays open until the server returns some data, at which point the client requests a new server connection.
In short, it’s a server request loop that might look something like this:
function longPoll() {
fetch('some_url_goes_here')
.then((response) => {
console.log('Data:', response.data);
// Do something with response.adta
longPoll(); // Establish a new network connection
})
,catch((error) => {
console.error(error);
// handle error
setTimeout(longPoll, 5000); // Attempt to reestablish connection
})
}
longPoll(); // Initiate long poll
This is an improvement insofar as network requests are only made once new data is available, but some drawbacks include relatively high latency and code complexity to ensure clients receive all events and updates—especially in edge caes, such as network reconnection.
Server-Sent Events
Server-sent events are a way to maintain a one-way, “read-only” connection, whereby a server can send live updates to a client—but a client cannot send writes over the same connection.
These connections can be written using the EventSource
API.
const eventSource = new EventSource('url_to_event_source')
eventSource.onmessage = (event) => {
console.log('Event message received': event.data);
// Handle generic message event here
}
eventSource.onerror = (event) => {
console.log('Error');
// Handle error event here
}
Some benefits to server-sent events include:
- Lower latencies than polling
- Automatic reconnection on connection loss
- Strict specifications—the server-sent script must set
Content-Type
totext/event-stream
and format messages according to the SSE specification. Some might consider this a detriment, as this adds to development complexity. - No HTTP request-response overhead
The obvious drawback of server-sent events is its unidirectionality; while it’s ideal for features such as live investment tracking, relaying of tournament scores, or other read-only bits of information, user interactions must be implemented through other channels.
Other drawbacks are that clients are limited to a maximum of six server-sent event connections (when not using server-sent events over HTTP/2
), and that data can only be UTF-8—no binary data.
WebSockets
The WebSocket API enables the implementation of a full-duplex interactive communication session between a client and a server via a single, lasting TCP connection. Like server-sent events, WebSockets enjoy lower-latencies and do not require the overhead of traditional HTTP request-response cycles.
WebSocket implementation using the WebSocket
API looks similar to that of server-sent events:
const socket = new WebSocket('ws_url_to_event_source')
socket.onopen = (event) => {
console.log('Connection established');
const payload = 'Create some payload here';
socket.send(payload);
}
socket.onmessage = (event) => {
console.log('Event message received', event.data);
// Handle socket event here
}
socket.onerror = (event) => {
console.log('Error');
// Handle error event here
}
There are a few crucial differences between WebSockets and server-sent events:
- WebSockets allow for bidirectional communication, where the client can call
socket.send
to communicate with the server. Because WebSockets, in general, leverage theHTTP/1.1
protocol, one muststringify
messages sent—and subsequentlyparse
messages received on the server. - WebSockets do not automatically attempt to reconnect on network connection loss. Moreover, WebSocket connections can be frustratingly fickle, and it can be difficult to determine whether a given socket connection can be reused or whether one must create a new WebSocket instance entirely.
- WebSockets require special
ws
protocl endpoints. - The client can theoretically open as many WebSocket connections as they want.
To handle WebSocket connection issues, developers often use a ping-pong heartbeat mechanism to ensure connections are not closed and implement functionality via the socket’s onclose
method to handle network reconnection.
Summary
There are other protocols as well, such as the WebTransport protocl and WebRTC, but neither are among the most commonly used methods of implementing real-time interactive web applications, which are summarized below:
Long Polling | WebSockets | Server-Sent Events | |
---|---|---|---|
Connection Direction | In general, one-way from server to client. | Bi-directional between server and client. | One-way, read-only connection from server to client. |
HTTP Overhead | High. (HTTP headers sent on every request) | Low. (HTTP/1.1 used to establish connection via handshake) | Low. (HTTP used to establish connection). Can be used over both HTTP/2 and HTTP/1.1 . |
Reconnect Handling | Manually coded timeout. | Manually coded onclose handler. | Automatic reconnect attempts. |
Backwards Compatability | Pretty much completely compatible. | Not polyfillable, but compatible with most browsers. | Polyfillable. |