Code Bytes
Refresh one part of a page with fetch
Poll a small same-origin JSON endpoint without overlapping requests, keep the last good value on failure and stop cleanly when the view is removed.
Update the value, not the whole page
Polling suits a small status display that changes occasionally. Fetch a compact response and update one text node; there is no need to reload the document or inject server-supplied HTML.
This example needs a real same-origin file or endpoint. It is not a live data service provided by this article. Create /status.json containing:
{ "message": "All services are available." }
Add readable initial content:
<p id="service-status">Check the service status for the latest update.</p>
<p id="status-notice" role="status"></p>
Poll without overlapping requests
function startStatusPolling(output, notice) {
let stopped = false;
let timer;
let controller;
let failures = 0;
async function refresh() {
if (stopped) return;
if (document.hidden) {
timer = setTimeout(refresh, 10000);
return;
}
controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 8000);
try {
const response = await fetch('/status.json', {
cache: 'no-store', credentials: 'same-origin',
signal: controller.signal,
});
if (!response.ok) throw new Error('Status unavailable');
const data = await response.json();
if (typeof data.message !== 'string' || data.message.length > 500) {
throw new Error('Unexpected status response');
}
if (!stopped) {
output.textContent = data.message;
notice.textContent = '';
failures = 0;
}
} catch {
failures = Math.min(failures + 1, 3);
if (!stopped) notice.textContent = 'Could not refresh. Showing the last available information.';
} finally {
clearTimeout(timeout);
controller = undefined;
if (!stopped) timer = setTimeout(refresh, Math.min(60000, 10000 * 2 ** failures));
}
}
refresh();
return () => {
stopped = true;
clearTimeout(timer);
controller?.abort();
};
}
const stopPolling = startStatusPolling(
document.querySelector('#service-status'),
document.querySelector('#status-notice'),
);
// Call stopPolling() when this component is removed.
What to change for your site
Serve the page over HTTP, not file://. Keep the endpoint small, set suitable server cache headers, and return only information that the visitor may see. The response-size check above limits the displayed message, not the total downloaded body; a public API should also enforce payload limits at the server.
Requests are spaced after completion, so a slow response does not create a pile of concurrent requests. Failures back off, preserve the last value and show a notice. Hidden tabs do not make requests. This is still polling, not guaranteed real-time delivery; for frequent events, evaluate a properly authenticated server-push design instead.
References: fetch and HTTP errors, timer scheduling, and page visibility.
Original version22 November 2013
Kept here for reference and earlier links. The updated guide above is the recommended starting point; older code may depend on retired services or different software versions.
The web has a wonderful ability to be dynamic, this is the way it should be.
We don't need to rely on the user to manually update/refresh to see the latest changes, we should hand it to them, that's what computers are for after all!
With the following Code Byte, I've constructed the most basic entry-level point to help turn your static web pages into dynamic and self-updating ones!
The idea:
We have a webpage that shows you the visitors your favourite number, that for some reason you decide to change every few minutes, the user doesn't have to refresh their browser, it's just automatically shown to them!
Here's how we do it:
You will need to create 2 files:
index.php
reload.txt (or name it whatever you like, just be sure to change the file name in the JavaScript section also).
The HTML:
<body onload="init()"> // Set up the initial JavaScript function, as shown in the JavaScript code.
<div id="main">
<div id="updateMe">
<h2>guwii's Favourite Number is:</h2>
<h1 id="guwiiFavouriteNumber"></h1>
</div>
</div>
</body>
The heart of it, the Java Script:
<script type="text/javascript">
function refresh() {
var req = new XMLHttpRequest();
console.log("Grabbing Value");
req.onreadystatechange = function () {
if (req.readyState == 4 && req.status == 200) {
document.getElementById('guwiiFavouriteNumber').innerText = req.responseText;
}
}
req.open("GET", 'reload.txt', true); // Grabs whatever you've written in this file
req.send(null);
}
function init() // This is the function the browser first runs when it's loaded.
{
refresh() // Then runs the refresh function for the first time.
var int = self.setInterval(function () {
refresh()
}, 10000); // Set the refresh() function to run every 10 seconds. [1 second would be 1000, and 1/10th of a second would be 100 etc.
}
</script>
Just place the HTML anywhere on your page, and the Javascript in the
<head>
of your HTML document.
How it works:
The init() function is run as soon as the page/browser is loaded, this initial function then sets up the required JavaScript.
It sets, via the self.setInterval() function, the refresh() function to run every 10 seconds.
The refresh() function then uses the built in JavaScript and web standard XMLHttpRequest(); to run the update.
It does this by using a GET (a computers way of grabbing a file/value) to the "reload.txt" file. The value within this file is then updated to the HTML element with an ID of "guwiiFavouriteNumber".
To test it, just save something different (or in keeping with our example, your ever-changing favourite number) in reload.txt and wait 10 seconds to see it change (or just change 10000 in the setInterval to 1000 to make it update every second!)
Note: To make this work you have to run it in a web environment. Eg, either on an actual website/server, or using a programme like WAMP/MAMP to set up a local web environment.
Feeling lazy? Here's the whole sh-bang:
<!DOCTYPE html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf8" />
<script type="text/javascript">
function refresh() {
var req = new XMLHttpRequest();
console.log("Grabbing Value");
req.onreadystatechange = function () {
if (req.readyState == 4 && req.status == 200) {
document.getElementById('guwiiFavouriteNumber').innerText = req.responseText;
}
}
req.open("GET", 'reload.txt', true);
req.send(null);
}
function init() {
refresh()
var int = self.setInterval(function () {
refresh()
}, 10000);
}
</script>
</head>
<body onload="init()">
<div id="main">
<div id="updateMe">
<h2>guwii's Favourite Number is:</h2>
<h1 id="guwiiFavouriteNumber"></h1>
</div>
</div>
</body>
</html>
From here...
Obviously, at the moment it's still grabbing a static number from a text document, this can, of course, be changed to a simple PHP file that calculates any kind of function that outputs a value. (Eg, a random number via PHP, your sales stats, your DOB, etc, wherever your imagination takes you!)
Keep exploring