In the previous post, we explored short polling. This time, let’s upgrade to long polling, a technique that keeps the client in sync with the server without frequent re-requests.


🧠 What’s Different?

In long polling:

  • Client sends a request and waits.
  • Server responds only when there is new data.
  • Once response is received, the client immediately resubscribes.

Let’s understand this using the core code blocks involved.


🧩 Server Code Highlights

1. Store connections for later use

const connections = [];

app.get('/subscribe', (req, res) => {
  if (req.query.data !== longPollingData) {
    return res.status(200).json({ message: longPollingData });
  }
  connections.push(res); // hold the response until new data is available
});

If the client already has the latest data, we hold the response (res) for future updates.

Otherwise, respond immediately.

2. Notify all clients on data update

app.post('/updateData', (req, res) => {
  longPollingData = req.body.userInput;

  connections.forEach((connection) => {
    connection.status(200).json({ message: longPollingData });
  });

  connections.length = 0;
  res.send('Update sent to all clients');
});
  • On receiving new data, we loop through all held responses and send the updated message.

  • Then, we clear the connections array.

Client Code Highlights

1. Subscribe and re-subscribe

const subscribe = async (lastData) => {
  try {
    const res = await fetch('/subscribe?data=' + lastData);
    const data = await res.json();

    updateData(data.message);
    await subscribe(data.message); // recursive re-subscribe
  } catch (err) {
    await new Promise((res) => setTimeout(res, 1000));
    await subscribe(lastData); // retry on failure
  }
};
  • Makes a /subscribe request and waits for server update.
  • Once update is received, it recursively re-subscribes.

2. Submit new data

form.addEventListener('submit', async (e) => {
  e.preventDefault();

  const inputValue = document.getElementById('userInput').value;

  await fetch('/updateData', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ userInput: inputValue }),
  });

  form.reset();
  updateData(inputValue);
});

Sends new input to server which triggers an update to all subscribed clients.

✅ Summary

Long polling holds client requests until new data is ready.

It’s efficient and feels real-time without setting up a WebSocket.


✅ Conclusion

Long polling offers a smarter alternative to short polling by reducing unnecessary traffic and keeping clients updated with minimal latency. While not as seamless as WebSockets, it's a practical solution for many use cases where persistent connections aren’t viable.


👍 Pros

  • Reduced network traffic compared to short polling.
  • Near real-time data delivery without constant re-requesting.
  • Works with HTTP/1.1, no need for WebSocket support.
  • Simple implementation using standard HTTP methods.

👎 Cons

  • ❌ Each update still requires a new HTTP connection.
  • ❌ More resource-intensive than WebSockets at scale.
  • Delayed response if no data is available for a while.
  • ❌ Not truly bi-directional — only server-to-client.

🕒 When to Use Long Polling

  • You need real-time-like updates, but WebSockets are not an option (e.g., firewalls, older infrastructure).
  • Your app doesn’t need constant updates but should reflect new data quickly.
  • You want a simpler alternative to WebSockets that works in most browsers.