<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Svitlana Lorman - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Svitlana Lorman - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 22:24:02 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/svlorman/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Server-Sent Events vs WebSockets – How to Choose a Real-Time Data Exchange Protocol ]]>
                </title>
                <description>
                    <![CDATA[ In our fast-paced digital era, real-time data exchange has become critical in creating responsive and dynamic user experiences. It’s especially important in applications like live news updates, chat systems, AI generative platforms, and so on. In thi... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/server-sent-events-vs-websockets/</link>
                <guid isPermaLink="false">677835cd5280589b2bc82110</guid>
                
                    <category>
                        <![CDATA[ development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ websockets ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Devops ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Developer ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Svitlana Lorman ]]>
                </dc:creator>
                <pubDate>Fri, 03 Jan 2025 19:09:01 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1734440242816/4ba6ef33-386a-45f7-872b-5974742855e2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In our fast-paced digital era, real-time data exchange has become critical in creating responsive and dynamic user experiences. It’s especially important in applications like live news updates, chat systems, AI generative platforms, and so on.</p>
<p>In this article, you’ll learn about <strong>WebSockets</strong> and <strong>Server-Sent Events (SSE)</strong>, two powerful communication protocols that ensure seamless, real-time interactions in modern web applications.</p>
<p>By examining their differences, advantages, and use cases, you’ll gain a clear understanding of how to choose the right protocol to optimize scalability and performance. This article also includes simple example implementations using <strong>Node.js</strong>, allowing you to see these technologies in action.</p>
<p>To help you solidify your knowledge further, we’ll conclude with practical project recommendations, offering hands-on opportunities to apply what you’ve learned.</p>
<h2 id="heading-table-of-contents">Table Of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-is-a-websocket">What is a WebSocket?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-advantages-of-websockets">Advantages and Disadvantages of WebSockets</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-use-cases-for-websockets">Use Cases for WebSockets</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-a-websocket-server-with-nodejs">How to Create a WebSocket Server with Node.js</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-are-server-sent-events-sse">What are Server-Sent Events (SSE)?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-advantages-of-server-sent-events">Advantages and Disadvantages of Server-Sent Events</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-use-cases-for-sse">Use Cases for SSE</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-implement-server-sent-events-using-node-js">How to Implement Server-Sent Events using Node.js</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-websockets-vs-server-sent-events">WebSockets vs Server-Sent Events</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-which-is-better-server-sent-events-or-websockets">Which is Better: Server-Sent Events or WebSockets?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-what-is-a-websocket"><strong>What is a WebSocket?</strong></h2>
<p>In short, a WebSocket is a communication protocol that enables full-duplex, low-latency, event-driven connections between the server and the browser. In case you’re not familiar, full-duplex refers to the ability to send and receive data simultaneously between a client (like a web browser) and a server over a single connection.</p>
<p>Unlike <a target="_blank" href="https://www.freecodecamp.org/news/what-is-http/">HTTP</a>, which operates in a request-response model, WebSockets enable persistent and continuous data exchange. This means that the data is exchanged in real-time, and pulling it from the server is unnecessary each time.</p>
<p>The WebSockets protocol was formalized in 2011 by the IETF through RFC 6455 and is now supported by all major browsers (Chrome, Edge, Safari, and so on).</p>
<p>Although WebSockets differ from HTTP, both protocols operate on the <a target="_blank" href="https://www.freecodecamp.org/news/osi-model-networking-layers-explained-in-plain-english/">OSI model’</a>s Application Layer (layer 7) and rely on <a target="_blank" href="https://www.freecodecamp.org/news/what-is-tcp-ip-layers-and-protocols-explained/">TCP/IP</a> at the Transport Layer (layer 4). The OSI (Open Systems Interconnection) model is a conceptual framework used to understand network communication. It divides the network into 7 layers, each responsible for a specific function, from physical data transmission to application-level interactions.</p>
<p>Similar to HTTP and HTTPS<em>,</em> WebSockets have a unique set of prefixes:</p>
<ul>
<li><p><strong>ws</strong>: indicates an unencrypted connection without TLS and should not be opened from HTTPS-secured sites.</p>
</li>
<li><p><strong>wss</strong>: indicates an encrypted connection secured by TLS and shouldn’t be opened from HTTP (non-secure) sites.</p>
</li>
</ul>
<h3 id="heading-how-do-websockets-work"><strong>How Do WebSockets Work?</strong></h3>
<p>As I mentioned earlier, WebSockets establish a persistent, bidirectional connection between the client and the server. The process begins with an HTTP handshake initiated by the client, where the client requests a WebSocket connection by sending a specific header to the server. If the server accepts the request, it responds with a status code 101 confirming the upgrade to a WebSocket connection.</p>
<p>Once the connection is established, the WebSocket protocol takes over, and both the client and the server can send and receive data at any time without the need for repeated handshakes. This continuous connection allows real-time communication with minimal latency, as data is exchanged immediately without waiting for additional requests.</p>
<p>The WebSocket connection remains open until either the client or server decides to close it. This ensures efficient and fast data exchange, making it ideal for real-time applications like chat systems, online gaming, or live data feeds.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735898910124/24538662-d00f-4457-a8a4-9da16f618046.png" alt="WebSocket full-duplex client-server connection " class="image--center mx-auto" width="1600" height="900" loading="lazy"></p>
<h3 id="heading-advantages-of-websockets"><strong>Advantages of WebSockets</strong></h3>
<ul>
<li><p><strong>Full-duplex connection</strong>: both client and server can send and receive data simultaneously.</p>
</li>
<li><p><strong>Low latency:</strong> since WebSockets maintain an open connection, they ensure minimal delay in data transfer by eliminating the overhead of repeatedly establishing and tearing down connections, ensuring minimal delay in data transfer.</p>
</li>
<li><p><strong>Reduced bandwidth usage:</strong> unlike HTTP requests, which include headers for every request, WebSockets only require a single handshake, resulting in smaller data packets and reduced bandwidth consumption.</p>
</li>
<li><p><strong>Cross-Platform Compatibility:</strong> as stated earlier, WebSockets are supported by most modern browsers and programming frameworks, which ensures broad applicability.</p>
</li>
</ul>
<h3 id="heading-disadvantages-of-websockets"><strong>Disadvantages of WebSockets</strong></h3>
<ul>
<li><p><strong>Complexity in implementation</strong>: WebSockets require a dedicated server and a special protocol.</p>
</li>
<li><p><strong>Vulnerability to attacks</strong>: Without proper security (wss prefix) and authentication mechanisms, WebSockets are susceptible to <a target="_blank" href="https://portswigger.net/web-security/websockets/cross-site-websocket-hijacking">cross-site WebSocket hijacking</a> (CSWSH) and <a target="_blank" href="https://www.ibm.com/think/topics/man-in-the-middle">man-in-the-middle (MITM)</a> attacks.</p>
</li>
<li><p><strong>No built-in security</strong>: Unlike HTTP, WebSockets do not inherently support request-response headers for additional security. Thus, it’s necessary to implement token-based authentication or other secure methods manually.</p>
</li>
</ul>
<h2 id="heading-use-cases-for-websockets"><strong>Use Cases for WebSockets</strong></h2>
<p>WebSockets have revolutionized how applications deliver real-time communication. This protocol powers various industries by enabling low-latency, bidirectional data flow. Let’s talk about some good use cases for WebSockets:</p>
<h3 id="heading-1-chat-applications">1. Chat Applications</h3>
<p>WebSockets’ full-duplex connection ensures that messages are delivered instantly and without interruptions, making them the perfect choice for real-time communication. This technology powers platforms like Slack, Discord, and various live customer support chat systems, providing seamless and efficient interactions.</p>
<h3 id="heading-2-online-gaming">2. Online Gaming</h3>
<p>WebSockets are essential for fast-paced online games like Clash Royal, where real-time communication between players and servers is crucial. By maintaining a persistent, two-way connection, WebSockets allow immediate transmission of actions, such as moves or attacks, ensuring that all players experience seamless gameplay without lag. </p>
<h3 id="heading-3-real-time-dashboards">3. Real-Time Dashboards</h3>
<p>Tools like Datadog and e-commerce platforms use WebSockets to ensure system metrics, sales, and inventory data are always current, eliminating manual refreshes and enhancing user experience.</p>
<p>WebSockets also excel at handling big data, streaming, and visualizing large volumes of information with low latency. This makes them the perfect choice for industries such as finance, healthcare, and logistics, where real-time insights are essential for effective decision-making. </p>
<p>An example is DataTableDev, a grid prototype capable of working with massive data volumes, demonstrating WebSockets’ potential in real-time data processing.</p>
<h2 id="heading-how-to-create-a-websocket-server-with-nodejs"><strong>How to Create a WebSocket Server with Node.js</strong></h2>
<p>Before setting up a simple WebSocket server with Node.js to handle secure connections, you’ll need a <a target="_blank" href="https://www.freecodecamp.org/news/what-is-tls-transport-layer-security-encryption-explained-in-plain-english/">TLS certificate</a> to ensure the communication is encrypted. You can acquire one from a trusted Certificate Authority (CA) like <a target="_blank" href="https://letsencrypt.org/">Let's Encrypt</a> or use a self-signed certificate for testing.</p>
<p>Below is the complete implementation of a WebSocket Secure (WSS) server using Node.js:</p>
<p>We’ll start on the server-side. Firstly, let’s import the required modules:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> https = <span class="hljs-built_in">require</span>(<span class="hljs-string">'https'</span>);  <span class="hljs-comment">// Module for creating an HTTPS server</span>
<span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>);        <span class="hljs-comment">// Module to read files (used to load TLS certificates)</span>
<span class="hljs-keyword">const</span> WebSocket = <span class="hljs-built_in">require</span>(<span class="hljs-string">'ws'</span>); <span class="hljs-comment">// WebSocket library to handle WebSocket connections</span>
</code></pre>
<p>Next, we’ll load TLS certificates for secure communication (wss://).</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> serverOptions = {
  <span class="hljs-attr">cert</span>: fs.readFileSync(<span class="hljs-string">'cert.pem'</span>), <span class="hljs-comment">// Load the TLS certificate for HTTPS encryption</span>
  <span class="hljs-attr">key</span>: fs.readFileSync(<span class="hljs-string">'key.pem'</span>),   <span class="hljs-comment">// Load the private key associated with the certificate</span>
};
</code></pre>
<p><code>serverOptions</code> reads the TLS certificate and private key from files (<code>cert.pem</code> and <code>key.pem</code>) and holds them. These are essential for establishing secure communication using the <code>wss://</code> protocol since they enable <strong>encryption</strong> for data transmitted between the server and the client.</p>
<p>Since the WebSocket server runs on top of the HTTPS server, we first create and initialize the HTTPS server using the <code>serverOptions</code>, and then set up the WebSocket server.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Create the HTTPS server with the loaded certificates and initialize it with TLS options</span>
<span class="hljs-keyword">const</span> httpsServer = https.createServer(serverOptions); 
<span class="hljs-comment">// Create a WebSocket server that runs on top of the HTTPS server</span>
<span class="hljs-keyword">const</span> wss = <span class="hljs-keyword">new</span> WebSocket.Server({ <span class="hljs-attr">server</span>: httpsServer });
</code></pre>
<p>Now it's time to define the behavior when a new WebSocket connection is established. You'll need to handle incoming messages from the WebSocket client, send a response back, and manage the disconnection process. In this tutorial, we'll keep it simple by printing the received data to the console.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Define the behavior when a new WebSocket connection is established</span>
wss.on(<span class="hljs-string">'connection'</span>, <span class="hljs-function">(<span class="hljs-params">ws</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Client connected'</span>);

  <span class="hljs-comment">// Handle incoming messages from the WebSocket client</span>
  ws.on(<span class="hljs-string">'message'</span>, <span class="hljs-function">(<span class="hljs-params">message</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Received: <span class="hljs-subst">${message}</span>`</span>); 
    ws.send(<span class="hljs-string">`Server received: <span class="hljs-subst">${message}</span>`</span>); <span class="hljs-comment">// Send a response back to the client</span>
  });

  <span class="hljs-comment">// Handle when a client disconnects</span>
  ws.on(<span class="hljs-string">'close'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Client disconnected'</span>);

  <span class="hljs-comment">// Send an initial message to the client when the connection is established</span>
  ws.send(<span class="hljs-string">'Welcome to the secure WebSocket server!'</span>);
});
</code></pre>
<p>Last but not least, you need to define the port where the HTTPS WebSocket server will listen for incoming connections. In this example, we use a port <code>8080</code>. After that, we start the HTTPS server and make it listen on the specified port. Once the server is up and running a log message will be printed to confirm that the secure WebSocket server is ready.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Define the port where the HTTPS WebSocket server will listen for incoming connections</span>
<span class="hljs-keyword">const</span> PORT = <span class="hljs-number">8080</span>;

<span class="hljs-comment">// Start the HTTPS server and begin listening on the specified port</span>
httpsServer.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Secure WebSocket server running at wss://localhost:<span class="hljs-subst">${PORT}</span>`</span>); <span class="hljs-comment">// Log a message when the server starts</span>
});
</code></pre>
<p>And that’s it for the server-side part. Your full code should look like this:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Import required modules</span>
<span class="hljs-keyword">const</span> https = <span class="hljs-built_in">require</span>(<span class="hljs-string">'https'</span>);  <span class="hljs-comment">// Module for creating an HTTPS server</span>
<span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>);        <span class="hljs-comment">// Module to read files (used to load TLS certificates)</span>
<span class="hljs-keyword">const</span> WebSocket = <span class="hljs-built_in">require</span>(<span class="hljs-string">'ws'</span>); <span class="hljs-comment">// WebSocket library to handle WebSocket connections</span>

<span class="hljs-comment">// Load TLS certificates for secure communication (wss://)</span>
<span class="hljs-keyword">const</span> serverOptions = {
  <span class="hljs-attr">cert</span>: fs.readFileSync(<span class="hljs-string">'cert.pem'</span>), <span class="hljs-comment">// Load the TLS certificate for HTTPS encryption</span>
  <span class="hljs-attr">key</span>: fs.readFileSync(<span class="hljs-string">'key.pem'</span>),   <span class="hljs-comment">// Load the private key associated with the certificate</span>
};

<span class="hljs-comment">// Create the HTTPS server with the loaded certificates and initialize it with TLS options</span>
<span class="hljs-keyword">const</span> httpsServer = https.createServer(serverOptions); 
<span class="hljs-comment">// Create a WebSocket server that runs on top of the HTTPS server</span>
<span class="hljs-keyword">const</span> wss = <span class="hljs-keyword">new</span> WebSocket.Server({ <span class="hljs-attr">server</span>: httpsServer }); 

<span class="hljs-comment">// Define the behavior when a new WebSocket connection is established</span>
wss.on(<span class="hljs-string">'connection'</span>, <span class="hljs-function">(<span class="hljs-params">ws</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Client connected'</span>); 

  <span class="hljs-comment">// Handle incoming messages from the WebSocket client</span>
  ws.on(<span class="hljs-string">'message'</span>, <span class="hljs-function">(<span class="hljs-params">message</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Received: <span class="hljs-subst">${message}</span>`</span>); 
    ws.send(<span class="hljs-string">`Server received: <span class="hljs-subst">${message}</span>`</span>); <span class="hljs-comment">// Send a response back to the client</span>
  });

  <span class="hljs-comment">// Handle when a client disconnects</span>
  ws.on(<span class="hljs-string">'close'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Client disconnected'</span>); 
  });
  <span class="hljs-comment">// Send an initial message to the client when the connection is established</span>
  ws.send(<span class="hljs-string">'Welcome to the secure WebSocket server!'</span>);
});

<span class="hljs-comment">// Define the port where the HTTPS WebSocket server will listen for incoming connections</span>
<span class="hljs-keyword">const</span> PORT = <span class="hljs-number">8080</span>;

<span class="hljs-comment">// Start the HTTPS server and begin listening on the specified port</span>
httpsServer.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Secure WebSocket server running at wss://localhost:<span class="hljs-subst">${PORT}</span>`</span>); <span class="hljs-comment">// Log a message when the server starts</span>
});
</code></pre>
<p>To run the created server with Node.js, type the following line into Command Prompt / Terminal:</p>
<p> <code>node wss-server.js</code></p>
<p>Connect to the server using a WebSocket client or browser console at <code>wss://</code><a target="_blank" href="http://localhost:8080"><code>localhost:8080</code></a>.</p>
<p>Once the connection is established, the client can send and receive messages. Now well look at a simple example of how to receive and send messages on the client side.</p>
<p>To start, let’s define a basic HTML structure:</p>
<pre><code class="lang-javascript">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
  &lt;meta charset="UTF-8"&gt;
  &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
  &lt;title&gt;WebSocket Client&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;h1&gt;WebSocket Client&lt;/h1&gt;
  &lt;div id="messages"&gt;&lt;/div&gt;
  &lt;input type="text" id="messageInput" placeholder="Type a message"&gt;
  &lt;button onclick="sendMessage()"&gt;Send Message&lt;/button&gt;

  &lt;script&gt;
    &lt;!-- JS code goes here --&gt;
  &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>The <code>&lt;button&gt;</code> element has an <code>onclick</code> event that triggers the <code>sendMessage()</code> function when clicked. Before we dive into the function, let's first establish a WebSocket connection to the server. We'll also define event listeners to handle the following:</p>
<ol>
<li><p>When the WebSocket connection is successfully established.</p>
</li>
<li><p>When a message is received from the server.</p>
</li>
</ol>
<p>These event listeners will ensure that we can interact with the server and handle incoming data in real time.</p>
<pre><code class="lang-javascript">    <span class="hljs-comment">// Establish a WebSocket connection to the server</span>
    <span class="hljs-keyword">const</span> socket = <span class="hljs-keyword">new</span> WebSocket(<span class="hljs-string">'wss://localhost:8080'</span>); 

    <span class="hljs-comment">// Event listener for when the WebSocket connection is established</span>
    socket.addEventListener(<span class="hljs-string">'open'</span>, <span class="hljs-function">() =&gt;</span> {
      displayMessage(<span class="hljs-string">'Connected to the WebSocket server'</span>);

    <span class="hljs-comment">// Event listener for when a message is received from the server</span>
    socket.addEventListener(<span class="hljs-string">'message'</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
      displayMessage(<span class="hljs-string">`Server: <span class="hljs-subst">${event.data}</span>`</span>); <span class="hljs-comment">// Display the message received from the server</span>
    });
</code></pre>
<p>To display the message on the user interface, we've created a function called <code>displayMessage</code>. Here's how it's defined:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Function to display messages in the message container</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">displayMessage</span>(<span class="hljs-params">message</span>) </span>{
      <span class="hljs-keyword">const</span> messageDiv = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'messages'</span>); <span class="hljs-comment">// Get the div where messages will be displayed</span>
      <span class="hljs-keyword">const</span> newMessage = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'p'</span>); <span class="hljs-comment">// Create a new paragraph element for the new message</span>
      newMessage.textContent = message; <span class="hljs-comment">// Set the text content of the paragraph to the message</span>
      messageDiv.appendChild(newMessage); <span class="hljs-comment">// Add the new paragraph to the message container</span>
}
</code></pre>
<p>Now, it’s time to define the <code>sendMessage()</code> function. Firstly, we retrieve a message and then send it to the WebSocket server using the <code>socket.send()</code> method. This transmits the message over the WebSocket connection established earlier, allowing the server to receive it. Next, on the UI, we display the message and clear the input field.</p>
<p>Thus, the code looks the following way:</p>
<pre><code class="lang-javascript">    <span class="hljs-comment">// Function to send a message to the server</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendMessage</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">const</span> message = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'messageInput'</span>).value; <span class="hljs-comment">// Get the message from the input field</span>
      socket.send(message); <span class="hljs-comment">// Send the message over the WebSocket connection</span>
      displayMessage(<span class="hljs-string">`You: <span class="hljs-subst">${message}</span>`</span>); <span class="hljs-comment">// Display the message in the UI as sent by the user</span>
      <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'messageInput'</span>).value = <span class="hljs-string">''</span>; <span class="hljs-comment">// Clear the input field after sending the message</span>
    }
</code></pre>
<p>The final step is to set the event listener for when the WebSocket connection closes. To keep it simple, we will log a message to the console.</p>
<pre><code class="lang-javascript"> socket.addEventListener(<span class="hljs-string">'close'</span>, <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Disconnected from the WebSocket server'</span>); 
 });
</code></pre>
<p>This is what the client-side part looks like:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>WebSocket Client<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>WebSocket Client<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"messages"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"messageInput"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Type a message"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"sendMessage()"</span>&gt;</span>Send Message<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-comment">// Establish a WebSocket connection to the server</span>
    <span class="hljs-keyword">const</span> socket = <span class="hljs-keyword">new</span> WebSocket(<span class="hljs-string">'wss://localhost:8080'</span>); <span class="hljs-comment">// Connect to WebSocket server </span>

    <span class="hljs-comment">// Event listener for when the WebSocket connection is established</span>
    socket.addEventListener(<span class="hljs-string">'open'</span>, <span class="hljs-function">() =&gt;</span> {
      displayMessage(<span class="hljs-string">'Connected to the WebSocket server'</span>);

    <span class="hljs-comment">// Event listener for when a message is received from the server</span>
    socket.addEventListener(<span class="hljs-string">'message'</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
      displayMessage(<span class="hljs-string">`Server: <span class="hljs-subst">${event.data}</span>`</span>); <span class="hljs-comment">// Display the message received from the server</span>
    });

    <span class="hljs-comment">// Function to send a message to the server</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendMessage</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">const</span> message = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'messageInput'</span>).value; <span class="hljs-comment">// Get the message from the input field</span>
      socket.send(message); <span class="hljs-comment">// Send the message over the WebSocket connection</span>
      displayMessage(<span class="hljs-string">`You: <span class="hljs-subst">${message}</span>`</span>); <span class="hljs-comment">// Display the message in the UI as sent by the user</span>
      <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'messageInput'</span>).value = <span class="hljs-string">''</span>; <span class="hljs-comment">// Clear the input field after sending the message</span>
    }

    <span class="hljs-comment">// Function to display messages in the message container</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">displayMessage</span>(<span class="hljs-params">message</span>) </span>{
      <span class="hljs-keyword">const</span> messageDiv = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'messages'</span>); <span class="hljs-comment">// Get the div where messages will be displayed</span>
      <span class="hljs-keyword">const</span> newMessage = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'p'</span>); <span class="hljs-comment">// Create a new paragraph element for the new message</span>
      newMessage.textContent = message; <span class="hljs-comment">// Set the text content of the paragraph to the message</span>
      messageDiv.appendChild(newMessage); <span class="hljs-comment">// Add the new paragraph to the message container</span>
    }

    <span class="hljs-comment">// Event listener for when the WebSocket connection is closed</span>
    socket.addEventListener(<span class="hljs-string">'close'</span>, <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Disconnected from the WebSocket server'</span>); 
    });
  </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<h2 id="heading-what-are-server-sent-events-sse"><strong>What are Server-Sent Events (SSE)?</strong></h2>
<p>Server-Sent Events (SSE) is a technology that enables a web server to push updates to a web page. As part of the HTML5 specification, it functions similarly to WebSockets by using a single, long-lived HTTP connection to deliver data in real-time.</p>
<p>The concept of SSE originated in 2004, with the <a target="_blank" href="https://blogs.opera.com/news/">Opera team</a> taking the first steps towards implementation in 2006. One of the main limitations of SSE in the early stages was the connection cap imposed by HTTP/1.1, which restricted the number of simultaneous connections a client could establish with a server. But with the introduction of HTTP/2, this limitation was removed. HTTP/2 allows multiple data streams to flow over a single connection through multiplexing, enabling more efficient and scalable communication for SSE.</p>
<p>Server-sent events (SSE) rely on two fundamental components:</p>
<ul>
<li><strong>EventSource</strong>: An interface defined by the WHATWG specification and implemented by modern browsers. It enables the client (typically a browser) to subscribe to server-sent events.  </li>
</ul>
<ul>
<li><strong>EventStream</strong>: A protocol that specifies the plain-text format servers must use to send events, ensuring compatibility with the EventSource client for seamless communication.  </li>
</ul>
<p>As the specification outlines, events can include arbitrary text data and an optional ID and are separated by newlines. Also, SSE events have a dedicated <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/MIME_types">MIME type</a>: <code>text/event-stream.</code> A MIME type (Multipurpose Internet Mail Extensions type) is a standard that indicates the nature and format of a file or data, allowing the browser or server to properly interpret and handle it.</p>
<h3 id="heading-how-do-server-sent-events-work"><strong>How do Server-Sent Events Work?</strong></h3>
<p>Server-sent events (SSE) work by establishing a persistent, one-way communication channel from the server to the client over a standard HTTP connection. The client initiates the connection by creating an <code>EventSource</code> object, which sends a request to the server to start streaming data. Once the server receives this request, it responds by sending a continuous stream of updates in a specific <code>text/event-stream</code> format. The client listens for these events, automatically handling any reconnections if the connection is lost.</p>
<p>SSE is ideal for applications that require real-time updates from the server, such as live news feeds or notifications, as it ensures a constant flow of information with minimal overhead.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735897258671/eec0599a-f5b5-43f2-8552-7f84ac265c3e.png" alt="This picture outlines how SSE works" class="image--center mx-auto" width="1600" height="900" loading="lazy"></p>
<h3 id="heading-advantages-of-server-sent-events"><strong>Advantages of Server-Sent Events</strong></h3>
<ul>
<li><p><strong>Polyfill capability</strong>: Server-sent events (SSE) can be implemented using JavaScript in browsers that don’t natively support them. This ensures backward compatibility by leveraging the standard SSE interface instead of creating a custom alternative.  </p>
</li>
<li><p><strong>Automatic reconnection</strong>: SSE connections are designed to reconnect automatically after interruption. Thus, they reduce the need for extra code to handle this essential functionality.  </p>
</li>
<li><p><strong>Firewall-friendly</strong>: SSEs work seamlessly with corporate firewalls that perform packet inspection, making them a reliable choice for enterprise applications.</p>
</li>
</ul>
<h3 id="heading-disadvantages-of-server-sent-events"><strong>Disadvantages of Server-Sent Events</strong></h3>
<ul>
<li><p><strong>Data format restrictions</strong>: SSE is restricted to transmitting messages in UTF-8 format, as it does not support binary data.  </p>
</li>
<li><p><strong>Connection limits</strong>: Browsers cap the number of simultaneous SSE connections to six per client. This limitation becomes problematic when multiple tabs require active SSE connections. For more details and potential workarounds, refer to this StackOverflow thread: <a target="_blank" href="https://stackoverflow.com/questions/18584525/server-sent-events-and-browser-limits">Server-Sent Events and browser limits</a>.</p>
</li>
<li><p><strong>One-way communication</strong>: SSE supports only server-to-client messaging, making it ideal for read-only real-time applications like stock tickers. However, this unidirectional nature can be a constraint for more interactive real-time applications.</p>
</li>
</ul>
<h2 id="heading-use-cases-for-sse"><strong>Use Cases for SSE</strong></h2>
<p>Server-sent events are widely used in applications where real-time data delivery is crucial. SSE enables the server to push updates to the client automatically, making it ideal for applications that require live information streams. From news feeds to financial dashboards, SSE ensures that users receive the latest content without constant page refreshes.</p>
<p>Here are some common use cases for using SSE:</p>
<h3 id="heading-1-social-media-feeds">1. Social Media Feeds</h3>
<p>Social media platforms leverage SSE to push new posts instantly, likes, and comments to users’ feeds, providing a more dynamic and engaging user experience. A great example is Twitter’s (X’s) real-time feed implementation, which allows them to push real-time updates to the browser.</p>
<h3 id="heading-2-enterprise-monitoring-system">2. Enterprise Monitoring System</h3>
<p>SSE enables financial monitoring systems and other real-time applications to deliver live data updates efficiently. For instance, Netflix’s open-source Hystrix, a well-known component for microservice monitoring and circuit breaking, includes a web dashboard that displays real-time performance metrics and circuit status. This dashboard uses SSE to push performance data in real-time, ensuring that users can monitor the health and performance of microservices as they happen. The dashboard leveraging SSE provides an efficient, low-latency solution for updating performance data without needing constant manual refreshing or polling.</p>
<h3 id="heading-3-generative-ai">3. Generative AI</h3>
<p>SSE technology plays a key role behind the scenes when interacting with Generative AI chatbots like ChatGPT and Gemini. For instance, when a user requests ChatGPT to write an article on a specific topic, the server starts processing the request and generates the article progressively, often in chunks rather than all at once.</p>
<p>During this process, ChatGPT’s server utilizes SSE to push each part of the article to the client in real-time, allowing the user to see the content appear as it is being generated. </p>
<h2 id="heading-how-to-implement-server-sent-events-using-nodejs"><strong>How to Implement Server-Sent Events using Node.js</strong></h2>
<p>In this section, we’ll explore how to implement SSE using Node.js, a popular JavaScript runtime, to push updates to the client in real-time. We’ll set up a basic server and send live data to the browser using SSE.</p>
<p>We’ll start with the client-side (HTML/JavaScript). First, we’ll create a new <code>EventSource</code> object to listen for events from the server.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> evtSource = <span class="hljs-keyword">new</span> EventSource(<span class="hljs-string">"sse-demo.js"</span>);
</code></pre>
<p>The URL <code>"sse-demo.js"</code> is the path to the server-side script that will generate the events. But if the event generator script were hosted on a different origin, we would need to provide an additional configuration for cross-origin requests.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// If the event generator script is hosted on a different origin (cross-origin request):</span>
<span class="hljs-keyword">const</span> evtSource = <span class="hljs-keyword">new</span> EventSource(<span class="hljs-string">"//api.example.com/sse-demo.js"</span>, {
  <span class="hljs-attr">withCredentials</span>: <span class="hljs-literal">true</span>,  <span class="hljs-comment">// Sends cookies, authorization headers with the request to the server</span>
});
</code></pre>
<p>This version ensures that cookies and authorization headers are sent with the request, enabling secure communication and making sure that credentials can be included in cross-origin requests. <code>withCredentials: true</code> ensures that authentication is handled correctly if needed.</p>
<p>Next, let’s set up an event listener to handle the message when it is received. To keep things simple, we will display the message on the user interface by adding it as a new list item.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// When a message event is received</span>
evtSource.onmessage = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-comment">// Create a new list item element to display the message</span>
  <span class="hljs-keyword">const</span> newElement = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"li"</span>);

  <span class="hljs-comment">// Get the reference to the unordered list element where messages will be displayed</span>
  <span class="hljs-keyword">const</span> eventList = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"list"</span>);

  <span class="hljs-comment">// Set the text content of the new list item to the message received</span>
  newElement.textContent = <span class="hljs-string">`message: <span class="hljs-subst">${event.data}</span>`</span>;

  <span class="hljs-comment">// Append the new list item to the event list (ul) in the HTML</span>
  eventList.appendChild(newElement);
};
</code></pre>
<p>Let's also add an event listener for a custom "ping" event. Again, we will simply add new data to the list and display it on the page. Thus, when the custom event is received, a new list item (<code>&lt;li&gt;</code>) is created.</p>
<p>The event data, which contains a <code>time</code> property, is parsed from JSON, and the time is displayed in the list item. This new list item is then appended to an unordered list (<code>&lt;ul&gt;</code>) in the HTML, allowing the "ping" event data to be shown on the user interface.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Add an event listener for a custom event type, "ping"</span>
evtSource.addEventListener(<span class="hljs-string">"ping"</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-comment">// Create a new list item element to display the ping event</span>
  <span class="hljs-keyword">const</span> newElement = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"li"</span>);

  <span class="hljs-comment">// Get the reference to the unordered list element where ping events will be displayed</span>
  <span class="hljs-keyword">const</span> eventList = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"list"</span>);

  <span class="hljs-comment">// Parse the event data as JSON (assuming it contains a time property)</span>
  <span class="hljs-keyword">const</span> time = <span class="hljs-built_in">JSON</span>.parse(event.data).time;

  <span class="hljs-comment">// Set the text content of the new list item to display the ping time</span>
  newElement.textContent = <span class="hljs-string">`ping at <span class="hljs-subst">${time}</span>`</span>;

  <span class="hljs-comment">// Append the new list item to the event list (ul) in the HTML</span>
  eventList.appendChild(newElement);
});
</code></pre>
<p>Make sure that your code for the client-side part looks like this:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Create a new EventSource to listen for events from the server</span>
<span class="hljs-keyword">const</span> evtSource = <span class="hljs-keyword">new</span> EventSource(<span class="hljs-string">"sse-demo.js"</span>);

<span class="hljs-comment">/* If the event generator script is hosted on a different origin (cross-origin request):
const evtSource = new EventSource("//api.example.com/sse-demo.js", {
  withCredentials: true,  // Sends cookies, authorization headers with the request to the server
});
*/</span>
<span class="hljs-comment">// When a message event is received</span>
evtSource.onmessage = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-comment">// Create a new list item element to display the message</span>
  <span class="hljs-keyword">const</span> newElement = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"li"</span>);

  <span class="hljs-comment">// Get the reference to the unordered list element where messages will be displayed</span>
  <span class="hljs-keyword">const</span> eventList = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"list"</span>);

  <span class="hljs-comment">// Set the text content of the new list item to the message received</span>
  newElement.textContent = <span class="hljs-string">`message: <span class="hljs-subst">${event.data}</span>`</span>;

  <span class="hljs-comment">// Append the new list item to the event list (ul) in the HTML</span>
  eventList.appendChild(newElement);
};

<span class="hljs-comment">// Add an event listener for a custom event type, "ping"</span>
evtSource.addEventListener(<span class="hljs-string">"ping"</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-comment">// Create a new list item element to display the ping event</span>
  <span class="hljs-keyword">const</span> newElement = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"li"</span>);

  <span class="hljs-comment">// Get the reference to the unordered list element where ping events will be displayed</span>
  <span class="hljs-keyword">const</span> eventList = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"list"</span>);

  <span class="hljs-comment">// Parse the event data as JSON (assuming it contains a time property)</span>
  <span class="hljs-keyword">const</span> time = <span class="hljs-built_in">JSON</span>.parse(event.data).time;

  <span class="hljs-comment">// Set the text content of the new list item to display the ping time</span>
  newElement.textContent = <span class="hljs-string">`ping at <span class="hljs-subst">${time}</span>`</span>;

  <span class="hljs-comment">// Append the new list item to the event list (ul) in the HTML</span>
  eventList.appendChild(newElement);
});
</code></pre>
<p>Now, let’s code the server-side part with Node.js and Express.js. Express is a minimal and flexible web application framework for Node.js. It simplifies the creation of server-side applications by providing robust features like routing, middleware support, and handling HTTP requests and responses. It helps streamline the development of web APIs and websites, making it perfect for our tutorial.</p>
<p>Note that you’ll need to go to the <a target="_blank" href="https://expressjs.com">official Express.js documentation</a> and install it on your machine if you don’t have it installed already.</p>
<p>Then, head over to the IDE and import the Express module, which allows us to create an instance of the Express application.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Import the Express module</span>
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-comment">// Create an instance of the Express application</span>
<span class="hljs-keyword">const</span> app = express();
</code></pre>
<p>It is considered good practice to specify the port number at the top of the file to make it easy to configure and modify later. This approach improves code readability and maintainability, allowing you to quickly change the port number without searching through the entire file. It also enables better flexibility when deploying the application in different environments (for example, development, staging, production).</p>
<p>For this tutorial, we have set the port number to <code>3000</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Define the port number for the server to listen on</span>
<span class="hljs-keyword">const</span> port = <span class="hljs-number">3000</span>;
</code></pre>
<p>Now, let's set up the server-side part with Node.js and Express to handle SSE requests. We define a route (<code>/sse</code>) that will send a continuous stream of events to the client.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Define a route that handles requests to /sse endpoint</span>
app.get(<span class="hljs-string">'/sse'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
<span class="hljs-comment">//....</span>
});
</code></pre>
<p>For the server to communicate with the client using SSE, we need to set specific HTTP headers:</p>
<ul>
<li><p><strong>Content-Type</strong>: We specify <code>'text/event-stream'</code> to let the client know that the response is an SSE stream.</p>
</li>
<li><p><strong>Cache-Control</strong>: Setting it to <code>'no-cache'</code> ensures the client gets fresh data each time, without caching.</p>
</li>
<li><p><strong>Connection</strong>: This is set to <code>'keep-alive'</code> to maintain the connection open for continuous data transmission.</p>
</li>
</ul>
<pre><code class="lang-javascript">app.get(<span class="hljs-string">'/sse'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-comment">// Set the Content-Type header to 'text/event-stream' to indicate that </span>
  <span class="hljs-comment">// the response will be an SSE stream</span>
  res.setHeader(<span class="hljs-string">'Content-Type'</span>, <span class="hljs-string">'text/event-stream'</span>);

  <span class="hljs-comment">// Prevent caching of the stream (important to ensure real-time updates)</span>
  res.setHeader(<span class="hljs-string">'Cache-Control'</span>, <span class="hljs-string">'no-cache'</span>);

  <span class="hljs-comment">// Keep the connection alive to continuously send events</span>
  res.setHeader(<span class="hljs-string">'Connection'</span>, <span class="hljs-string">'keep-alive'</span>);
});
</code></pre>
<p>You can use <code>res.flushHeaders()</code> to send the headers immediately. Thus, the client can begin listening for events without delay.</p>
<p>To add a bit of flair, let's send a new SSE message every second, including the number of the message being sent. For this, we will initialize a variable <code>counter</code> , as well as to use <code>setInterval</code> to send a new message every second (1000ms).</p>
<pre><code class="lang-javascript">app.get(<span class="hljs-string">'/sse'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-comment">// Set the Content-Type header to 'text/event-stream' to indicate that </span>
  <span class="hljs-comment">// the response will be an SSE stream</span>
  res.setHeader(<span class="hljs-string">'Content-Type'</span>, <span class="hljs-string">'text/event-stream'</span>);

  <span class="hljs-comment">// Prevent caching of the stream (important to ensure real-time updates)</span>
  res.setHeader(<span class="hljs-string">'Cache-Control'</span>, <span class="hljs-string">'no-cache'</span>);

  <span class="hljs-comment">// Keep the connection alive to continuously send events</span>
  res.setHeader(<span class="hljs-string">'Connection'</span>, <span class="hljs-string">'keep-alive'</span>);

  <span class="hljs-comment">// Send the headers immediately, so the client starts listening for events</span>
  res.flushHeaders();

  <span class="hljs-comment">// Initialize a counter variable for the messages</span>
  <span class="hljs-keyword">let</span> counter = <span class="hljs-number">0</span>;

  <span class="hljs-comment">// Use setInterval to send a new message every second (1000ms)</span>
  <span class="hljs-built_in">setInterval</span>(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// Send a new SSE message, incrementing the counter each time</span>
    <span class="hljs-comment">// Each message is prefixed with 'data: ' and followed by the message content</span>
    res.write(<span class="hljs-string">`data: This is message <span class="hljs-subst">${counter++}</span>\n\n`</span>);
  }, <span class="hljs-number">1000</span>); <span class="hljs-comment">// This interval runs every 1000 milliseconds (1 second)</span>
});
</code></pre>
<p>The last step is to start the Express server the following way:</p>
<pre><code class="lang-javascript">app.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server running at http://localhost:<span class="hljs-subst">${port}</span>`</span>);
});
</code></pre>
<p>And that’s it! Make sure your server-sent code looks like this:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Import the Express module</span>
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-comment">// Create an instance of the Express application</span>
<span class="hljs-keyword">const</span> app = express();

<span class="hljs-comment">// Define the port number for the server to listen on</span>
<span class="hljs-keyword">const</span> port = <span class="hljs-number">3000</span>;

<span class="hljs-comment">// Define a route that handles requests to /sse endpoint</span>
app.get(<span class="hljs-string">'/sse'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-comment">// Set the Content-Type header to 'text/event-stream' to indicate that </span>
  <span class="hljs-comment">// the response will be an SSE stream</span>
  res.setHeader(<span class="hljs-string">'Content-Type'</span>, <span class="hljs-string">'text/event-stream'</span>);

  <span class="hljs-comment">// Prevent caching of the stream (important to ensure real-time updates)</span>
  res.setHeader(<span class="hljs-string">'Cache-Control'</span>, <span class="hljs-string">'no-cache'</span>);

  <span class="hljs-comment">// Keep the connection alive to continuously send events</span>
  res.setHeader(<span class="hljs-string">'Connection'</span>, <span class="hljs-string">'keep-alive'</span>);

  <span class="hljs-comment">// Send the headers immediately, so the client starts listening for events</span>
  res.flushHeaders();

  <span class="hljs-comment">// Initialize a counter variable for the messages</span>
  <span class="hljs-keyword">let</span> counter = <span class="hljs-number">0</span>;

  <span class="hljs-comment">// Use setInterval to send a new message every second (1000ms)</span>
  <span class="hljs-built_in">setInterval</span>(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// Send a new SSE message, incrementing the counter each time</span>
    <span class="hljs-comment">// Each message is prefixed with 'data: ' and followed by the message content</span>
    res.write(<span class="hljs-string">`data: This is message <span class="hljs-subst">${counter++}</span>\n\n`</span>);
  }, <span class="hljs-number">1000</span>); <span class="hljs-comment">// This interval runs every 1000 milliseconds (1 second)</span>
});

<span class="hljs-comment">// Start the Express server and listen on the specified port</span>
app.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server running at http://localhost:<span class="hljs-subst">${port}</span>`</span>);
});
</code></pre>
<h2 id="heading-websockets-vs-server-sent-events"><strong>WebSockets vs Server-Sent Events</strong></h2>
<p>The goal of data transfer methods is to load and display large datasets as quickly as possible. This ensures that the user perceives the response as instant and provides smooth navigation and a pleasant user experience.</p>
<p><a target="_blank" href="https://www.nngroup.com/articles/author/jakob-nielsen/">Jakob Nielsen</a>, a retired principal and co-founder of the Nielsen Norman Group, outlined three key time limits that developers should consider when optimizing web and application performance in his book <a target="_blank" href="https://www.nngroup.com/books/usability-engineering/">Usability Engineering</a>. In short, 0.1 seconds is the threshold for users to feel that the system is responding instantaneously, meaning that no special feedback is required other than simply displaying the result.</p>
<p><a target="_blank" href="https://www.linkedin.com/in/vera-didenko/">Vera Didenko</a>, Software Architect and Developer at Flexmonster conducted research to identify the most efficient data transfer protocol and, based on the 100-millisecond constraint, calculated the time budget for each process, ultimately choosing WebSockets as the optimal method for loading and updating the data.</p>
<p><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXe5vtbDVh_QdPm4ajDMJ3Gc2l6sF-TZs4YhzZEXLbj0fbsm1iW71lNu7X7TGuu6uUnXZSUPsPWZPjviWFcYnSZFALba9qoGgbHICv6z635gn2Ie9pvYjsv3-n0M7aZCe6Hy7kXNpC5I4P6k0YBqBcg?key=p_cDJW9Yx9AjWig3CS4ijdeZ" alt="  Extended tolerable response time from Jakob Nielsen’s “Usability Engineering”." width="600" height="400" loading="lazy"></p>
<p>For research purposes, Vera created an application using .NET Core and <a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/signalr/overview/getting-started/introduction-to-signalr">SignalR</a> to test and visually compare the performance of WebSockets and Server-Sent Events to discover which data transfer approach is the most performance-efficient. SignalR is an open-source library that simplifies real-time web functionality.</p>
<p>After running several tests for all methods simultaneously while increasing the number of calls each time, the test results were gathered in JSON format and fed to the <a target="_blank" href="https://www.amcharts.com/">amCharts library</a>. Below are the test results for 100, 1000, and 10000 calls:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735051327581/c940c14c-636b-4cfc-b55f-5e1fd4f11370.png" alt="The performance of WebSockets and Server-Sent Events" class="image--center mx-auto" width="1425" height="682" loading="lazy"></p>
<p>The experiment results show that WebSockets perform best for this task, emerging as the most performance-efficient data transfer technology in the simulated scenarios.</p>
<h3 id="heading-which-is-better-server-sent-events-or-websockets"><strong>Which is Better: Server-Sent Events or WebSockets?</strong></h3>
<p>SSE is a simpler solution, but it isn't extensible: if your web application <a target="_blank" href="https://www.amcharts.com/">r</a>equirements were to change, it would likely need to be refactored using WebSockets. Also, with AI integration SSE becomes even more powerful and secure.</p>
<p>Although WebSocket technology presents more upfront work, it's a more versatile and extensible framework, so it’s a better option for complex applications that are likely to add new features over time.</p>
<table><tbody><tr><td><p>Feature</p></td><td><p>WebSockets</p></td><td><p>Server-Sent Events&nbsp;</p></td></tr><tr><td><p>Communication</p></td><td><p>Full-duplex (two-way)</p></td><td><p>One-way (server-to-client)</p></td></tr><tr><td><p>Data Type Support</p></td><td><p>Binary and text</p></td><td><p>Text (UTF-8 encoded only)</p></td></tr><tr><td><p>Connection Limits</p></td><td><p>Limited by server resources</p></td><td><p>Limited by browser (e.g. 6 tabs)</p></td></tr><tr><td><p>Reconnection</p></td><td><p>Requires manual handling</p></td><td><p>Automatic</p></td></tr><tr><td><p>Protocol</p></td><td><p>Custom, low-level protocol</p></td><td><p>Built on HTTP</p></td></tr><tr><td><p>Firewall Handling</p></td><td><p>May face problems</p></td><td><p>Work seamlessly</p></td></tr><tr><td><p>Use Case Examples</p></td><td><p>real-time, event-driven communication between clients and servers, such as online games, chats, etc</p></td><td><p>streaming data uni-directionally (i.e., “one direction”) from server to client for streaming data like stock quotes, bitcoin prices, etc</p></td></tr></tbody></table>

<p>In practice, many developers prefer WebSockets even for scenarios requiring receiving information rather than opting for SSE. This preference is not solely due to the limitations of SSE—such as its reliance on keeping a connection open for continuous data flow—but also because WebSockets offer greater versatility and are often considered more future-proof.</p>
<p>For instance, popular platforms like Reddit and Trello choose WebSockets to receive data (Reddit and Trello only send information to users when they are offered to subscribe to another person).</p>
<p>From personal experience, I can point out that SSE data often doesn’t appear in the developer tools, making it harder to debug and inspect. You can verify this by checking a web application like ChatGPT, where no SSE data sent by the server is visible in the developer tools network tab. This lack of transparency can make working with SSE more challenging than the more straightforward, visible data flow provided by WebSockets.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>I hope this article was both interesting and useful to you! If you want to further strengthen your knowledge and take your skills to the next level, I highly recommend diving into real-life projects.</p>
<p>Personally, I found these on freeCodeCamp to be really useful and even a bit challenging: <a target="_blank" href="https://www.freecodecamp.org/news/build-a-logging-web-app-with-server-sent-events-rxjs-and-express/">How to Build a Logging Web App with Server-Sent Events, RxJS, and Express and Learn WebSockets with Socket.IO</a>. Not only will these projects give you hands-on experience, but they will also provide you with valuable new insights and skills that you can apply to future development challenges.</p>
<p>Happy coding, and keep learning!</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
