fetch() – načítání dat ze serveru
Doposud JavaScript pracoval jen s tím, co je přímo na stránce. Funkce fetch() otevírá nový svět: umožňuje načítat data ze serveru nebo z externího API bez obnovení celé stránky. Díky ní může web zobrazit aktuální počasí, načíst výsledky vyhledávání nebo odeslat formulář – a vše tiše na pozadí, bez přerušení práce uživatele.
Co je fetch() a jak funguje?
fetch() je zabudovaná funkce prohlížeče pro síťové požadavky. Posílá HTTP požadavek na zadanou URL a vrátí Promise – příslib budoucí odpovědi. Síťový požadavek totiž chvíli trvá a JavaScript nesmí mezitím zamrznout.
Základní použití:
fetch('https://api.example.com/data')
.then(function (odpoved) {
// Požadavek proběhl – ale data jsou zatím surová odpověď
return odpoved.json(); // převede tělo odpovědi na JavaScriptový objekt
})
.then(function (data) {
// Zde máme hotová data jako objekt nebo pole
console.log(data);
})
.catch(function (chyba) {
// Síťová chyba nebo jiný problém
console.error('Chyba při načítání:', chyba);
});
Metoda .then() říká: „Až bude odpověď připravena, udělej toto.\" Metoda .catch() zachytí případnou chybu. Toto je tzv. řetězení Promises.
Modernější zápis – async/await
Novější a přehlednější způsob práce s Promises je klíčové slovo async/await. Kód pak vypadá téměř jako synchronní, přestože čeká na síťový požadavek:
async function nactiData() {
try {
let odpoved = await fetch('https://api.example.com/data');
// Ověření HTTP statusu
if (!odpoved.ok) {
throw new Error('Server vrátil chybu: ' + odpoved.status);
}
let data = await odpoved.json();
console.log(data);
return data;
} catch (chyba) {
console.error('Chyba:', chyba.message);
}
}
// Zavolání funkce
nactiData();
Klíčové slovo await lze použít jen uvnitř funkce označené async. Blok try/catch nahrazuje .catch() z předchozího zápisu.
Načítání JSON dat z API
Nejčastější použití fetch() je načtení dat z veřejného API. Ukázka s veřejným API pro náhodné citáty:
async function nactiCitat() {
let oblast = document.getElementById('citat-oblast');
oblast.textContent = 'Načítám citát…';
try {
let odpoved = await fetch('https://api.quotable.io/random');
if (!odpoved.ok) throw new Error('HTTP ' + odpoved.status);
let data = await odpoved.json();
// data.content = text citátu, data.author = autor
oblast.textContent = `„${data.content}" — ${data.author}`;
} catch (chyba) {
oblast.textContent = 'Citát se nepodařilo načíst.';
}
}
document.getElementById('btn-nacist').addEventListener('click', nactiCitat);
Odeslání dat na server – metoda POST
Výchozí metoda fetch() je GET (stažení dat). Pro odeslání dat se použije POST s tělem požadavku:
async function odesliFormalur(jmeno, email, zprava) {
try {
let odpoved = await fetch('https://formspree.io/f/tvujkod', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ jmeno, email, zprava })
});
if (odpoved.ok) {
document.getElementById('zprava').textContent = 'Odesláno, díky!';
} else {
throw new Error('Odeslání se nezdařilo.');
}
} catch (chyba) {
document.getElementById('zprava').textContent = chyba.message;
}
}
Načítání lokálních souborů
fetch() funguje i pro lokální soubory na stejném serveru – například HTML stránky lekcí, JSON soubory s daty nebo textové soubory:
// Načtení HTML lekce pro vyhledávání (přesně jak funguje web_search.js)
async function nactiLekci(url) {
try {
let odpoved = await fetch(url);
if (!odpoved.ok) return '';
let html = await odpoved.text(); // .text() místo .json() pro HTML
return html;
} catch {
return '';
}
}
// Použití
let obsah = await nactiLekci('web/w.css_grid.html');
// obsah je celý HTML soubor jako řetězec
Metoda .text() vrátí tělo odpovědi jako prostý řetězec – hodí se pro HTML, CSV nebo jakýkoliv nJSON obsah.
Načítání dat a přístupnost
Při dynamickém načítání dat je důležité informovat uživatele odečítače o stavu operace:
- Před načítáním nastav text oblasti na „Načítám…\" –
aria-live="polite"oblast ho přečte. - Po načtení vlož výsledek do stejné
aria-liveoblasti – VoiceOver automaticky oznámí změnu. - Při chybě zobraz srozumitelnou hlášku v
aria-live="assertive"oblasti. - Tlačítko pro spuštění načítání by mělo být dočasně označeno jako zaneprázdněné:
button.setAttribute('aria-busy', 'true').
async function nactiSData(btn, oblast) {
btn.setAttribute('aria-busy', 'true');
btn.disabled = true;
oblast.textContent = 'Načítám data…';
try {
let odpoved = await fetch('…');
let data = await odpoved.json();
oblast.textContent = data.text;
} catch {
oblast.textContent = 'Nepodařilo se načíst data. Zkus to znovu.';
} finally {
btn.setAttribute('aria-busy', 'false');
btn.disabled = false;
}
}
Tip od Zdeňka
Zdeněk radí: Funkce fetch() je výkonný nástroj, ale s jednou záludností: HTTP chyby (404, 500) ji samy o sobě nevyhodí do catch – musíš sám zkontrolovat odpoved.ok nebo odpoved.status. Do catch se dostaneš jen při skutečné síťové chybě (žádné připojení, timeout). Tento detail přehlédne spousta začátečníků a pak se diví, proč kód „funguje\" i když server vrátí 404. Vždy proto píši if (!odpoved.ok) throw new Error(…) hned za await fetch() – ušetří to hodiny ladění.