What are real-time web applications, and what technologies help us implement them?
Real-time web application offers an enhanced web experience and are becoming increasingly more common. Users appreciate when they can simply open the page and the browsers gets updated whenever the contents on the server change. However, if you tried to implement a real-time web app today, you'd run into a few issues. The main culprit for those is the communication model underlying HTTP: a synchronous client-server exchange, in which the client always initiates the request, and the server always responds to it.
But what if the server wants to initiate a conversation with the client? Some applications require such features. Imagine sending updated stock prices, or delivering messages to members of a web chatroom. Generally, any time we wish to send a state-change from server to connected clients, we need something to enable the server to initiate communication.
In traditional applications, this isn't possible. To see an update, the user has to refresh the page. To simulate real-time updates in traditional approaches, we have to use a workarounds, such as AJAX polling or long polling.
On the other hand, server-sent events and web sockets are modern, HTML5 approaches that offer a much more seamless experience. However, they have their own caveats as well. In this article, we briefly go over mentioned approaches.
The most typical implementation of a real-time web app with a traditional approach is AJAX polling. Here we use JavaScript on the client to poll the server with some predefined frequency. Every time the update is requested, the client sends a full-fledged HTTP request. The server then responds with an HTTP response containing either the updated data, or a messages signaling no update is available.
While this works, and has an update delay inversely proportional to the polling frequency, it is rather wasteful, as it creates significant overhead: you have to set up a new TCP connection and potentially negotiate new security parameters every time an update is requested. And while some performance improvement can be made, the generated overhead remains considerable. Moreover, the load on the server increases dramatically: a mere set of 1000 clients each polling every 5 seconds, would generate 12,000 requests/minute.
Long polling is an attempt to reduce the overhead of AJAX polling. Here, after the client sends the HTTP request, the server waits until updated data is available. Only then it returns the HTTP response containing the data. Because of this longer wait time, long polling is also known as the hanging GET
. Immediately after receiving the response, the client sends another request, and the wait for new data continues.
Long polling does not generate empty HTTP responses when the server does not have updates. However, full-fledged HTTP requests are still required for every update. Depending on the frequency with which updates are created, this can significantly reduce the load on the server compared to AJAX polling.
Today, WebSockets are a go-to solution for real-time web applications. They offer fast, two-way communication between a browser and a server, making them ideal for scenarios where speed is vital, like fast-paced multiplayer games. However, web sockets work differently from traditional HTTP requests and responses.
A WebSocket connection starts with a classic HTTP request, which the server responds to with an HTTP response with code 101 Switching Protocols
and a few response headers. The connection then switches over to a bidirectional and binary protocol in which either side can send messages at any time. Consequently, the underlying TCP connection becomes long-lived: it stays active as long as the client keeps the page open.
However, WebSockets are not without limitations. For one, they don't work on top of HTTP, but rather next to it. This means that WebSockets cannot take advantage of certain HTTP features, like compression and HTTP/2 multiplexing. Additionally, WebSockets may have some issues in deployment where proxies are used, and because they work independently of HTTP connections, certain security concerns, such as same-origin policies, need to be handled manually. Developers are still working on ways to improve this situation.
Furthermore, since the WebSocket protocol is binary, developers need to adapt it to suit their use-case. While libraries of today do most of the heavy lifting regarding binary encoding, developers are still responsible for defining application-level protocol messages. This also means that among all real-time web application approaches, WebSockets are also the most complex.
![img](https://bunnyacademy.b-cdn.net/web sockets.svg "Web Sockets: A bidirectional protocol where the server and the client can arbitrarily send messages.")
Server-sent Events (SSE) sit somewhere between classic approaches and web sockets: they have the simplicity of traditional approaches while offering certain, but not all, functionality of WebSockets.
With Server-Sent Events, the client initiates a request to the server, just like in traditional HTTP protocol, and the server responds normally, except that now the response body never ends – it is infinite. The server keeps the underlying TCP connection open (it is long-lived), and when it has updates to send, it simply writes them to the response stream where they are immediately received by the client.
An obvious advantage is that the server can now send updates instantly without client's explicit request. However, compared to web sockets, SSE are unidirectional, meaning that only the server can send data. (The client can of course always send data to the server with traditional HTTP request, but that has to occur over a different TCP connection.) This limitation may not be suitable for all applications.
That being said, the data flow in many real-time applications is asymmetric: most of it is sent by the server while clients mostly listen and send only occasionally. Even in a chatroom setting, most of the data will often be coming from the server: in a chatroom with many users and public rooms, most of the traffic will be messages being sent from the server to clients. If the volume of data going from the server to clients considerably exceeds the volume in the other direction, the SSE may still be a good choice.
Each of the four technologies has its benefits and drawbacks. The best choice always depends on the application requirements and the underlying web application stack.
AJAX polling is the simplest and can be applied to basically any web application stack. An obvious limitation is its inefficiency and wastefulness when the polling frequency is high.
Long-polling, on the other hand, is more efficient, but puts a larger strain on the server regarding the number of concurrently open connections; not a strategy that every web server appreciates.
WebSockets are the most powerful and efficient, but also the most complex. Moreover, they require a web application stack that supports long-lived connections: once the HTTP protocol upgrades to the WebSocket protocol, the underlying TCP connection has to be kept open until the client is connected.
Web application stacks that work synchronously with one-process-per-request strategy, which is typical in a LAMP setting, will be terribly inefficient when the number of clients becomes large: if every client gets its own process, the server will eventually run out of available processes. Asynchronous web framework that can handle multiple connections concurrently by using non-blocking I/O are best for such use cases.
Similarly, Server-Sent Events also require a web application stack that supports long-lived connections, but compared to WebSockets are less complex, text-based, and unidirectional.
Hypertext Transfer Protocol. A protocol that connects web browsers to web servers when they request content.
Server-Sent Events. A protocol that lets a client receive messages from a server.
A protocol for real-time communication through a sustained TCP connection.
A protocol for real-time communication where the client and server send HTTP requests and responses repeatedly over a period of time.
A protocol for real-time communication where the client sends HTTP requests repeatedly over a period of time, but the server only responds when it has new information.