DEV Community

Cover image for Real-time Updates: Polling, SSE and Web Sockets
Sanjeev Sharma
Sanjeev Sharma

Posted on

Real-time Updates: Polling, SSE and Web Sockets

Cover image by Martin Jaros on Unsplash.

Hey ๐Ÿ‘‹

If you are a junior or mid-level front-end developer ๐Ÿ‘จโ€๐Ÿ’ป, chances are you might have implemented something that needs real-time updates. Maybe a notification system, a chat-application, an upload progress bar or social media status indicator.

Making a chat app is on everyone's to-do list. I know that because I have been through that phase too. I built one while following a YouTube tutorial. ๐Ÿคทโ€โ™‚๏ธ The same tutorial that has been uploaded by almost every YouTube channel out there: using socket.io.

Mr. Bean Copying

Did you know that socket.io uses Web sockets under the hood? Yeah, you probably know this. But are real-time updates only possible with web sockets? ๐Ÿคจ No. This is not the only way. There are few other methods as well that we'll be looking at in this article. ๐Ÿ‘‡

We'll be covering three techniques/technologies:

  1. Polling + Long Polling
  2. Server Sent Events
  3. Web Sockets (in brief)

I've tried my best to explain these with illustrations. ๐ŸŽจ

Polling

This is the simplest approach to follow when building a real-time app.

In polling, client makes the request to the server repeatedly in hope for updated/new data. No extra steps are required to achieve this. Just wrap your API call with setInterval and you're done. In layman's terms, It's like refreshing your web page every time after few seconds.

Polling Illustration

Maybe you receive updated data or maybe not. There's no way to know this beforehand.

const URL = 'https://jsonplaceholder.typicode.com/posts/';

const fetchPosts = async () => {
  try {
    console.log('Fetching new data...');

    const response = await (await fetch(URL)).json();

    console.log('Data fetched!')

  } catch(err) {
    console.log('Request failed: ', err.message);
  }
}

setInterval(fetchPosts, 5000);
Enter fullscreen mode Exit fullscreen mode

Long Polling

Since we're on this topic it's worth talking about Long Polling here. Long Polling is the genius/optimized version of polling.

Instead of sending a response immediately, server waits until it has some new data for client. Client starves for a response; which is actually fine because client is not blocked and keeps on doing other tasks. It's understood here that this requires some effort on server-side as well.

Long Polling Illustration

Once the client receives the data, it has to create another request for the next state of data.

const URL = "https://jsonplaceholder.typicode.com/posts";

const fetchPosts = async () => {
  try {
    console.log("Fetching new data...");

    const response = await (await fetch(URL)).json();

    console.log("Data fetched!");

    return response;
  } catch (err) {
    console.log("Request failed: ", err.message);
  }
};

const longPoll = async () => {
  // response might be delayed as server might not have updated data
  const response = await fetchPosts();

  if (response) {
    return longPoll();
  }

}

longPoll();

Enter fullscreen mode Exit fullscreen mode

Note: These snippets provide the bare minimum just to convey the idea. You might wanna add more functionalities to this like attempts count or delay. It'd also be nice to add some checks in your code so you don't end up DOSing your own server. ๐Ÿ’ฉ

Server Sent Events

This is my favorite part of this article. I recently learnt about SSE while working at Syfe(we're hiring!). Before these I only knew about web sockets and used those, even for small apps. SSE are powerful, simple and get the job done with minimal code. ๐Ÿ‘Œ

In SSE, client makes the initial request to the server to set up a connection. Post that server pushes updated data to client whenever it is available. No further engagement is required from client. Of course client needs to handle those events but that's it.

Server Sent Events Illustration

// server-side code in express

app.get("/real-time-updates", (req, res) => {
  res.setHeader("Content-Type", "text/event-stream");

  const sendRealTimeUpdates = () => {
    res.write("data: New data!\n\n");
    setTimeout(sendRealTimeUpdates, 3000);
  };

  sendRealTimeUpdates();
});

Enter fullscreen mode Exit fullscreen mode

This is the shortest implementation possible.

  1. We created a GET route /real-time-updates.
  2. Set the Content-Type header as text/event-stream.
  3. Use res.write() to send data to client. If we use res.send() or res.end() it will close the connection.

๐Ÿ‘‰ Important points to note

  1. The message should always start with data:. Yes! space too.
  2. The message should always end with \n\n.

We've simulated real-time updates by wrapping res.write with a setTimeout.

// client-side code in vanilla JS

const URL = 'http://127.0.0.1:3000/real-time-updates';

const sseClient = new EventSource(URL);

sseClient.onopen = () => console.log('Connection opened!');

sseClient.onmessage = (event) => console.log(event.data);

sseClient.onerror = () => console.log('Something went wrong!');

Enter fullscreen mode Exit fullscreen mode

We use EventSource interface for setting up a connection with SSE end point.

  1. Get an instance of client using EventSource. Pass the URL you want to subscribe to.
  2. We get 3 event handlers that are called a different stages.
    • onopen is called when the connection opens.
    • onerror is called when an error occurs.
    • onmessage is called when we receive an event from server and we don't handle that event explicitly.
  3. We also get a close method that can be used to close the connection anytime.

If we don't specify an event type on the server, by default, every event has the type message. Hence, the handler onmessage which catches every event.

But if we specify an event using event: keyword we can handle it explicitly on the client.

// diff: server-side code with custom event

res.write("event: notification\ndata: New data!\n\n");
Enter fullscreen mode Exit fullscreen mode
// diff: client-side code with custom event handling

sseClient.addEventListener('notification', (event) => {
    console.log(event.data))
};
Enter fullscreen mode Exit fullscreen mode

That's all the code you need to add your own SSE. ๐Ÿค“

โš ๏ธ When SSE is implemented over HTTP/1.1, it suffers from a limitation of maximum number of connections; which is 6. That means any website www.fake-dev.to can open upto 6 SSE connections in a browser(multiple tabs included). It's advised to use HTTP/2, which has default limit of 100, but can be configured.

Web Sockets

Web Sockets are more powerful than the above mentioned methodologies but they come with additional complexities.

Web Sockets form a duplex connection, which means both client and sever can send data to each other on a single channel whereas SSE are uni-directional.

Web Sockets are initiated by an HTTP request for hankshake but later they are upgraded to TCP layer.

Web Sockets Illustration

HTTP protocol is a stateless protocol, which means all the headers including cookies, tokens, etc. are sent with every request. This makes it horizontally scalable. If server 1 is over loaded, request can be handled by server 2 and since we have all the information in the headers it would make no difference. This also makes it slow, as more data needs to be sent with every request. Also, the connection is closed as soon as request is fulfilled. So, for a new request the connection has to be opened again which is time consuming.

On the other hand, TCP is stateful. Web sockets are faster because connection is kept alive for communication and no additional headers are sent with each request. But this is also makes it a bit harder to scale. If the client was talking to server 1 then all the requests should be handled by server 1 only. Other servers are not aware about it's state.


You after reading this article

With all this being said, there is no perfect solution. Depending on the use case one might be better than other but it's good to know all the possible alternatives. ๐Ÿ’ช

๐Ÿ’ก There's a new API under development known as WebTransport based on HTTP/3, which is meant for low latency, bi-directional, multiplexed, client-server messaging.

๐Ÿ“Œ Save this for later.

That's all folks! Thank you for reading. ๐Ÿ™


I hope you liked this article. If you like to see content related to front-end development, you can connect with me on LinkedIn or Twitter.

๐Ÿ•Š

Discussion (12)

Collapse
dinniej profile image
Nguyen Ngoc Dat

Polling/Long Polling: Mails dashboard like Gmail
Web Socket: RTC application
SSE: This is the first time I read about this, but I think this will be great with server monitoring systems since we only need one side response from the server

Collapse
thesanjeevsharma profile image
Sanjeev Sharma Author

Excellent examples! You understand it right.

Collapse
liyasthomas profile image
Liyas Thomas

This is very informative. Learned a lot about real-time APIs.

If anyone like to spin up a any such realtime APIs (SSE, Socket.IO, WebSocket etc.) online - checkout Hoppscotch.io - helps to make and test real-time requests directly from the browser.

GitHub logo hoppscotch / hoppscotch

๐Ÿ‘ฝ Open source API development ecosystem - https://hoppscotch.io

Collapse
thesanjeevsharma profile image
Sanjeev Sharma Author

Thanks, Liyas!

And yes hoppscotch is awesome. ๐Ÿ‘Œ

Collapse
liviufromendtest profile image
Liviu Lupei • Edited on

This was a great read! Thank you for writing such a detailed article.
We have a bunch of real-time updates ourselves at Endtest.
When a user is running an automated on our platform, they get real-time logs, screenshots and live video.
And we're always looking to improve the performance for that.

Collapse
thesanjeevsharma profile image
Sanjeev Sharma Author

I'm glad I could be of some help. :)

Collapse
jamessspanggg profile image
James Pang

Nice one Sanjeev!

Collapse
thesanjeevsharma profile image
Sanjeev Sharma Author

Thanks, bruh!

Collapse
makx profile image
Makx

Good article. Concise and informative.

Collapse
thesanjeevsharma profile image
Sanjeev Sharma Author

Thank you! :)

Collapse
near2542 profile image
near2542

Thanks !! I'm now more confident to implement some of these.

Collapse
thesanjeevsharma profile image
Sanjeev Sharma Author

I'm glad I could help.