Load JSON data with fetch, wait for it with await, show it on the page, and fall back to a saved copy when the network fails.
Weather apps, maps and live scores all ask a server for data while the page is open, then show it.
So far every page had its data written in it. fetch asks for data from a file or a server while the page is open. The reply takes time to arrive, so the code waits for it:
async function load() {
const response = await fetch("weather.json"); // ask, and wait for the reply
const data = await response.json(); // turn the reply into data, and wait
// now use data
}
load();
{ } objects and [ ] arrays as JavaScript. weather.json sits beside the page here: a saved forecast for Canberra from Open-Meteo.await waits for something slow; it only works inside a function marked async.try { … } catch (error) { … } runs a plan B when something in try fails, such as no network.This is the same idea as Data detective's weather lesson in Python, if you have done it.
Make your prediction first. Help opens once you've locked it in.
<h1>Canberra this week</h1>
<p id="out">Loading…</p>
<script>
async function load() {
const response = await fetch("weather.json");
const data = await response.json();
document.querySelector("#out").textContent = "Top on the first day: " + data.daily.temperature_2m_max[0] + " °C";
}
load();
</script>
weather.json holds a week of temperatures. The page starts with Loading….
Press Run. The list is made with the createElement and append you already know, one item per day.
<h1>Canberra this week</h1>
<p id="status">Loading…</p>
<ul id="days"></ul>
<p><small>Weather data by Open-Meteo.com (CC BY 4.0)</small></p>
<script>
async function load() {
const response = await fetch("weather.json");
const data = await response.json();
const days = data.daily;
for (let i = 0; i < days.time.length; i++) {
const li = document.createElement("li");
li.textContent = days.time[i] + ": " + days.temperature_2m_min[i] + " to " + days.temperature_2m_max[i] + " °C";
document.querySelector("#days").append(li);
}
document.querySelector("#status").textContent = "The saved forecast";
}
load();
</script>
<h1>Canberra this week</h1>
<p id="status">Loading…</p>
<ul id="days"></ul>
<p><small>Weather data by Open-Meteo.com (CC BY 4.0)</small></p>
<script>
async function load() {
const response = await fetch("weather.json");
const data = await response.json();
const days = data.daily;
for (let i = 0; i < days.time.length; i++) {
const li = document.createElement("li");
li.textContent = days.time[i] + ": " + days.temperature_2m_min[i] + " to " + days.temperature_2m_max[i] + " °C";
document.querySelector("#days").append(li);
}
document.querySelector("#status").textContent = "The saved forecast";
}
load();
</script>
Ask, turn into data, show.
Things that take time.
Data that has not arrived.
Put the lines in order: ask for the file, turn the reply into data, then show the first day.
The page stays on Loading… and shows a red error: Cannot read properties of undefined. Click the line that is wrong.
The live forecast comes from Open-Meteo, a free weather service with no sign-up. If your school's network blocks it, the page should still work: that is what the saved copy is for.
<script>
try {
// fetch the live forecast from URL
} catch (error) {
// plan B: fetch the saved copy, weather.json
}
</script>
One more list from the data.
weather.json has a third list beside the temperatures: precipitation_sum, the rain in mm.
Add + ", rain " + days.precipitation_sum[i] + " mm" to the end of each line's text.

Try, and catch.
Wrap the live fetch in try. In catch, fetch weather.json instead. Either way, data ends up holding the forecast.
let data; try { const response = await fetch(URL); data = await response.json(); } catch (error) { … the same two lines with "weather.json" … }
Show each day's rain too.
This ticks when your page has all of the above.
Load the live forecast from URL, and fall back to weather.json when that fails.
This ticks when your page has all of the above.
Find the hottest day in the data (a loop that remembers the best so far, and an if that checks each day against it) and show it in the status line, with its date and temperature.
Show the hottest day of the week, found with a loop and an if.
This ticks when your page has all of the above.
You can now load data while the page is open. Apps with Vue builds pages that follow their data; Data detective does the same in Python.
Students predict that a page shows Loading before fetched data arrives, order the lines that load JSON, find a missing await, add rain to the forecast, load the live forecast with a saved copy as plan B, and find the week's hottest day. About 55 minutes.
Open the teacher guide: answers, solutions, slides and a worksheet.
An optional lesson at the end of the DOM course. fetch("weather.json") asks for a file (or a web address) and gives back a promise, a value that arrives later. await waits for it, and only works inside an async function. The reply is text; await response.json() turns it into JavaScript objects and arrays. Forgetting the second await is the planted bug: data is then a promise, so data.daily is undefined.
weather.json is a saved week of Canberra temperatures from Open-Meteo, the same file as Data detective's weather lesson in Python (dates are when it was saved). The live task asks Open-Meteo, a free service with no account or key. try … catch loads the saved copy when the live request fails, which is also what happens if the school network blocks the site, so check it before class with the Check your school page.
Weather data by Open-Meteo.com, licensed CC BY 4.0: the credit line stays on the page.
The order of events is the hard part: the rest of the page runs before the data arrives. Ask "has the data arrived yet at this line?" rather than fixing their awaits for them.
Stretch: Show the forecast as bars with widths from the temperatures; add a Refresh button that calls load() again; load a different town by changing the latitude and longitude in the URL.
Support: Give the try and catch written out; students change only what the status line says.
Apps with Vue: a fetch in a setup function that sets a ref. Data detective does the same in Python with requests. Class idea: list apps on a phone that fetch data, and what each would show with no connection.