Challenge 2: Implement Naive Polling, Then Improve It — Possible Solution ==================================================================== // --- Naive polling --- async function pollStatus() { const response = await fetch("/api/status"); const status = await response.json(); renderStatus(status); } setInterval(pollStatus, 5000); // check every 5 seconds, regardless of whether anything changed // --- Long polling improvement --- async function longPollStatus() { try { // /api/status/wait is described (not implemented here) as an endpoint // that holds the HTTP request open on the SERVER side until the // status actually changes, or a server-side timeout (e.g. 30s) is // reached — at which point it responds with either the new status // or a "no change" signal. const response = await fetch("/api/status/wait"); const status = await response.json(); renderStatus(status); } catch (err) { console.error("Long-poll request failed, retrying shortly:", err); await new Promise((resolve) => setTimeout(resolve, 2000)); // brief backoff on error } longPollStatus(); // immediately re-issue the request, whether we got new data or timed out } longPollStatus(); // start the loop once, rather than on an interval THE CONCRETE DIFFERENCE IN LATENCY AND REQUEST VOLUME ----------------------------------------------------------- Naive polling (5-second interval): - If the status changes right after a poll just returned, the client won't find out for up to ~5 seconds (the worst-case latency equals the polling interval). - Over one minute, this makes exactly 12 requests, REGARDLESS of whether the status ever actually changed — most of those requests return "nothing new," which is pure wasted server load and network traffic. Long polling: - The moment the server-side status changes, the held-open request for /api/status/wait can respond IMMEDIATELY — latency drops to (near) the time it takes the change to happen and the response to reach the client, not the polling interval. - Request volume now scales with how often changes ACTUALLY OCCUR (plus one request per server-side timeout, if nothing changes for the full timeout window) rather than a fixed rate regardless of activity — if status changes twice in a minute, only ~2-3 requests happen, not 12. WHY THIS WORKS -------------- - The core mechanical difference is WHERE the waiting happens: naive polling has the CLIENT wait (via setInterval) and ask repeatedly; long polling has the SERVER wait (holding the request open) and respond only when there's something worth responding with. - The client-side loop structure changes too: naive polling uses setInterval to trigger a NEW independent request on a fixed schedule; long polling uses a self-continuing loop (each response immediately triggers the next request) with no fixed interval at all — the "wait" is baked into each individual request rather than the loop. - A brief backoff on error (the catch block) prevents a broken connection from turning into a tight, rapid-fire retry loop that would hammer the server — a small but important resilience detail long polling implementations need that a simple setInterval loop doesn't.