← Back to the library
FrontendApplied · 7 min

The app hangs once users open a few tabs

“With one or two tabs everything works. Open a sixth or seventh and new tabs spin forever: API calls sit as Pending in DevTools, and closing an old tab instantly unblocks them.”

THE PRINCIPLE

Long-lived requests consume a shared, per-origin connection budget; count them across tabs, not per page.

FIRST MOVES

  1. Check the Protocol column in DevTools Network for the stream: http/1.1 means you're on the 6-connection limit. Look for requests stalled in the Queueing phase.
  2. Serve the stream origin over HTTP/2 or HTTP/3 at the hop the browser talks to (CDN, load balancer, or proxy); streams then multiplex on one connection (the concurrent-stream limit is negotiated, commonly 100).
  3. Share one connection across tabs: elect a leader tab with the Web Locks API and fan events out with BroadcastChannel, or hold the EventSource in a SharedWorker.
  4. Close streams in hidden tabs when freshness doesn't matter there, and reopen them on visibilitychange. A new EventSource doesn't send Last-Event-ID (only its own automatic reconnects do), so pass the last seen ID in the URL to catch up.

TOOLS: THEN → NOW

Separate subdomains to get more HTTP/1.1 connectionsHTTP/2 or HTTP/3 multiplexing on one origin
One EventSource per tabLeader tab via Web Locks plus BroadcastChannel, or a SharedWorker (Baseline since 2026)

PATTERN SNAPSHOT

const channel = new BroadcastChannel("live-events");
channel.onmessage = (e) => render(e.data); // followers just listen

// Only one tab per origin holds the lock; the next one takes over if it closes.
navigator.locks.request("live-events-leader", () => new Promise<never>(() => {
  const source = new EventSource("/events");
  source.onmessage = (e) => {
    const data = JSON.parse(e.data);
    render(data);             // BroadcastChannel doesn't echo to the sender
    channel.postMessage(data);
  };
}));

CLOSE THE AI. EXPLAIN THIS.

Why can a seventh tab break ordinary fetch() calls even though only the SSE stream holds connections open?

HOW IT WORKS UNDERNEATH

SOURCES

Guide reviewed