Published on

Server Sent Events in Node.js: A Comprehensive Guide (with Polling, Long Polling, and Nodemon)

Authors

Introduction

In the world of real-time web applications, there are several techniques to achieve real-time communication between the server and the client. Server-Sent Events (SSE), Polling, and Long Polling are some of the most common approaches. While WebSockets often steal the spotlight, SSE provides a simple and efficient way to push updates from the server to the client over a single HTTP connection. In this blog, we’ll explore what Server-Sent Events are, how they compare to Polling and Long Polling, and how to implement SSE in Node.js. We’ll also use Nodemon to automatically restart our Node.js server during development.


What are Server-Sent Events (SSE)?

Server-Sent Events (SSE) is a standard that allows a server to send real-time updates to a client over a single, long-lived HTTP connection. Unlike WebSockets, which enable full-duplex communication (both client and server can send messages), SSE is unidirectional—only the server can send data to the client. This makes SSE ideal for scenarios where the server needs to push updates, such as live notifications, stock tickers, or real-time analytics.

SSE is built on top of HTTP, making it easy to implement and integrate with existing web applications. It uses the text/event-stream content type and sends data in a specific format, which the client can parse and handle.


Polling and Long Polling

Before diving into SSE, let’s briefly discuss two other techniques for real-time communication: Polling and Long Polling.

Polling

Polling is a technique where the client repeatedly sends requests to the server at regular intervals to check for updates. While simple to implement, polling can be inefficient because it involves frequent HTTP requests, even when there are no updates. This can lead to unnecessary network traffic and server load.

Example of Polling

setInterval(() => {
    fetch('/updates')
        .then(response => response.json())
        .then(data => console.log(data));
}, 5000); // Poll every 5 seconds

Long Polling

Long Polling is an improvement over regular polling. Instead of sending requests at fixed intervals, the client sends a request to the server and waits for a response. The server holds the request open until new data is available or a timeout occurs. Once the client receives a response, it immediately sends another request. This reduces the number of requests compared to regular polling but can still be resource-intensive.

Example of Long Polling

function longPoll() {
    fetch('/updates')
        .then(response => response.json())
        .then(data => {
            console.log(data);
            longPoll(); // Send another request immediately
        });
}
longPoll();

Comparison with SSE

Polling: Inefficient due to frequent requests. Long Polling: Better than polling but still involves repeated connections. SSE: Efficient and persistent, with the server pushing updates to the client over a single connection.

Implementing SSE in Node.js with Nodemon

Let’s dive into how to implement Server-Sent Events in a Node.js application. We’ll use Nodemon to automatically restart the server whenever we make changes to our code. This is especially useful during development.

Step 1: Set Up a Node.js Project

First, create a new Node.js project and install the necessary dependencies:

mkdir sse-example
cd sse-example
npm init -y
npm install express nodemon

Step 2: Create the Server

Create a file named server.js and add the following code:

const express = require('express');
const app = express();

app.get('/events', (req, res) => {
    // Set headers for SSE
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');
    res.setHeader('Access-Control-Allow-Origin', '*');

    // Send a message every 2 seconds
    const intervalId = setInterval(() => {
        const data = JSON.stringify({ message: `Hello at ${new Date().toLocaleTimeString()}` });
        res.write(`data: ${data}\n\n`); // SSE format
    }, 2000);

    // Clean up on client disconnect
    req.on('close', () => {
        clearInterval(intervalId);
        res.end();
    });
});

app.listen(3000, () => {
    console.log('Server is running on http://localhost:3000');
});

Step 3: Configure Nodemon

To use Nodemon, update the scripts section in your package.json file:

"scripts": {
  "start": "node server.js",
  "dev": "nodemon server.js"
}

Now, you can start the server in development mode using:

npm run dev

Nodemon will automatically restart the server whenever you make changes to server.js.

Step 4: Create the Client

Create an index.html file to consume the SSE stream:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SSE Example</title>
</head>
<body>
    <h1>Server-Sent Events Example</h1>
    <div id="messages"></div>

    <script>
        const eventSource = new EventSource('http://localhost:3000/events');

        eventSource.onmessage = (event) => {
            const data = JSON.parse(event.data);
            const messageElement = document.createElement('p');
            messageElement.textContent = data.message;
            document.getElementById('messages').appendChild(messageElement);
        };

        eventSource.onerror = () => {
            console.error('EventSource failed.');
            eventSource.close();
        };
    </script>
</body>
</html>

Step 5: Run the Application

  1. Start the server in development mode: npm run dev.
  2. Open the index.html file in your browser.
  3. You should see real-time messages appearing every 2 seconds.

Use Cases for Server-Sent Events

SSE is particularly useful in scenarios where the server needs to push updates to the client without requiring bidirectional communication. Some common use cases include:

  1. Real-Time Notifications: Push notifications for new messages, alerts, or updates.
  2. Live Feeds: Display live updates such as news feeds, sports scores, or stock prices.
  3. Progress Updates: Show progress for long-running tasks like file uploads or data processing.
  4. Dashboards: Update dashboards with real-time metrics and analytics.
  5. Chat Applications: Send messages to clients in a one-way chat system.

UPros of Server-Sent Events

Simplicity: SSE is easy to implement and uses standard HTTP, making it compatible with existing infrastructure. Automatic Reconnection: The client automatically reconnects if the connection is lost. Efficient: SSE uses a single HTTP connection, reducing overhead compared to polling. Browser Support: SSE is supported in most modern browsers, including Chrome, Firefox, Safari, and Edge. No Need for Additional Libraries: Unlike WebSockets, SSE doesn’t require additional libraries or protocols.


Cons of Server-Sent Events

Unidirectional: SSE only allows the server to send data to the client. If bidirectional communication is needed, WebSockets are a better choice.

Limited Browser Support in Older Browsers: Older browsers like Internet Explorer do not support SSE.

Connection Limits: Browsers impose a limit on the number of simultaneous HTTP connections, which can be a bottleneck for applications with many clients.

No Binary Data: SSE is limited to text-based data, making it unsuitable for scenarios requiring binary data transfer


When to Use SSE vs. Polling vs. WebSockets

Use Polling for simple use cases where real-time updates are not critical, and you want a straightforward implementation.

Use Long Polling when you want to reduce the number of requests compared to regular polling but don’t need the efficiency of SSE.

Use SSE when you only need server-to-client communication and want a simple, lightweight solution.

Use WebSockets when you need full-duplex communication or have more complex real-time requirements.


Conclusion

Server-Sent Events are a powerful tool for building real-time web applications. They are simple to implement, efficient, and well-suited for scenarios where the server needs to push updates to the client. By using Nodemon, we can streamline the development process and automatically restart the server whenever changes are made.

If you’re building a real-time application in Node.js, consider giving SSE a try. It might just be the perfect solution for your needs!


Happy coding!