Fetch API

Вітаю знову.
У попередній лекції ти познайомився з local storage.
Local storage дозволяє JavaScript запамʼятовувати маленькі шматочки даних у браузері.
Дуже корисно.
Дуже практично.
Дуже в стилі: “браузер тепер має маленький блокнот.”
Сьогодні ми навчимо JavaScript отримувати дані ззовні сторінки.
І тут усе стає дуже реальним.
Вебсайти рідко тримають усі дані в одному JavaScript-файлі.
Вони часто завантажують дані з:
- API;
- серверів;
- JSON-файлів;
- баз даних через backend endpoints;
- інших сервісів.
Щоб отримати ці дані, JavaScript використовує Fetch API.
Fetch дозволяє JavaScript попросити дані.
Браузер каже:
Я піду й принесу.
JavaScript відповідає:
Добре. Тільки, будь ласка, не повертайся з хаосом.
Іноді він повертається з даними.
Іноді — з помилкою.
Іноді — з чимось, що змушує тебе переосмислити життєві рішення.
Вітаю у веброзробці.
Що Ти Вивчиш
У цій лекції ти вивчиш:
- що таке Fetch API;
- що таке JSON;
- чому
fetch()є асинхронним; - як завантажити локальний JSON-файл;
- як використовувати
asyncіawait; - як перетворити response у JSON;
- як показувати loading-повідомлення;
- як обробляти помилки через
tryіcatch; - як показувати завантажені дані в DOM;
- як створити маленький список товарів.
Наприкінці цієї лекції твоя сторінка завантажуватиме дані з JSON-файлу й показуватиме їх на екрані.
Це величезний крок.
До цього більшість даних жила прямо в JavaScript.
Тепер JavaScript почне брати дані ззовні.
Як frontend-посланець.
У кращому взутті.
Що Таке Fetch?
fetch() — це JavaScript-функція для запиту даних.
Приклад:
fetch("products.json");
Це просить браузер завантажити файл products.json.
Але є важливий момент.
fetch() не повертає дані миттєво.
Це займає час.
Навіть якщо файл маленький.
Навіть якщо файл локальний.
Навіть якщо ти просиш дуже ввічливо.
Тому JavaScript сприймає fetch() як асинхронну операцію.
Це означає:
Почни запит зараз.
Продовжуй, коли результат буде готовий.
Це важливо.
Дуже важливо.
Інтернет не миттєвий.
Навіть коли прикидається таким.
Що Таке JSON?
JSON означає JavaScript Object Notation.
Це текстовий формат для зберігання й передачі даних.
Він схожий на JavaScript-обʼєкти.
Приклад JSON:
{
"name": "JavaScript Course",
"price": 49,
"available": true
}
JSON всюди.
API використовують JSON.
Backend-и повертають JSON.
Frontend-застосунки читають JSON.
Твій майбутній backend на Java Spring Boot, швидше за все, теж буде віддавати JSON.
А frontend буде пити його як каву.
Обережно.
Бо поганий JSON приносить сум.
Створи Проєкт
Створи папку для цієї лекції:
mkdir javascript-lesson11
cd javascript-lesson11
touch index.html
touch script.js
touch products.json
Твій проєкт має виглядати так:
javascript-lesson11/
index.html
script.js
products.json
Важливо:
У цій лекції не відкривай index.html напряму подвійним кліком.
Бо fetch() може неправильно завантажувати локальні файли через file://.
Використай локальний сервер.
Наприклад, з Caddy:
caddy file-server --listen :8080
Потім відкрий:
http://localhost:8080
Тепер браузер зможе нормально завантажити JSON-файл.
Без framework-дракона.
Просто маленький локальний сервер.
Цивілізовано.
Напиши JSON-Файл
Відкрий products.json і додай:
[
{
"id": 1,
"name": "JavaScript Course",
"price": 49,
"available": true
},
{
"id": 2,
"name": "HTML Course",
"price": 29,
"available": true
},
{
"id": 3,
"name": "CSS Course",
"price": 39,
"available": false
}
]
Це масив обʼєктів.
Кожен обʼєкт представляє один товар.
Кожен товар має:
id;name;price;available.
Це дуже поширено.
Список товарів?
Масив обʼєктів.
Список користувачів?
Масив обʼєктів.
Список постів блогу?
Масив обʼєктів.
JavaScript бачить масиви обʼєктів всюди.
Як голубів на площі.
Напиши HTML
Відкрий index.html і додай:
<!DOCTYPE html>
<html lang="uk">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fetch API</title>
</head>
<body>
<h1>Fetch API</h1>
<button id="loadButton">Завантажити Товари</button>
<p id="message">Натисни кнопку, щоб завантажити товари.</p>
<ul id="productList"></ul>
<script src="script.js"></script>
</body>
</html>
Маємо:
- кнопку;
- місце для повідомлення;
- список для товарів.
Просто.
Чисто.
Готово отримувати дані.
Сторінка чекає.
Як офіціант з порожнім підносом.
Твій Перший Fetch
Відкрий script.js і додай:
const loadButton = document.getElementById("loadButton");
const messageElement = document.getElementById("message");
const productListElement = document.getElementById("productList");
async function loadProducts() {
const response = await fetch("products.json");
const products = await response.json();
console.log(products);
}
loadButton.addEventListener("click", loadProducts);
Запусти локальний сервер:
caddy file-server --listen :8080
Відкрий:
http://localhost:8080
Натисни кнопку.
Відкрий консоль.
Ти маєш побачити масив товарів.
Вітаю.
JavaScript завантажив дані з JSON-файлу.
Це реально.
Маленьке реально.
Але реально.
Розуміння async і await
Подивись на цю функцію:
async function loadProducts() {
const response = await fetch("products.json");
const products = await response.json();
console.log(products);
}
Слово async означає:
Ця функція виконує асинхронну роботу.
Слово await означає:
Почекай, поки ця операція завершиться, перед тим як рухатися далі.
Цей рядок:
const response = await fetch("products.json");
чекає, поки файл завантажиться.
Цей рядок:
const products = await response.json();
чекає, поки response перетвориться у JavaScript-дані.
Без await JavaScript не чекає.
А потім код стає розгубленим.
Як намагатися їсти пасту до того, як вона зварилася.
Технічно можливо.
Емоційно неправильно.
Що Таке response?
fetch() дає нам обʼєкт response.
Приклад:
const response = await fetch("products.json");
Response містить інформацію про запит.
Це ще не фінальні дані.
Щоб отримати JSON-дані, ми використовуємо:
const products = await response.json();
Це перетворює тіло response у JavaScript-дані.
Важливо:
response.json() також асинхронний.
Тому ми використовуємо await.
JavaScript потрібен момент, щоб прочитати й розпарсити JSON.
Навіть JavaScript потребує хвилинку.
Поважай процес.
Показ Товарів на Сторінці
Тепер покажемо товари в DOM.
Онови script.js:
const loadButton = document.getElementById("loadButton");
const messageElement = document.getElementById("message");
const productListElement = document.getElementById("productList");
async function loadProducts() {
const response = await fetch("products.json");
const products = await response.json();
productListElement.innerHTML = "";
for (const product of products) {
const listItem = document.createElement("li");
listItem.textContent = `${product.name} - €${product.price}`;
productListElement.appendChild(listItem);
}
messageElement.textContent = `Завантажено товарів: ${products.length}.`;
}
loadButton.addEventListener("click", loadProducts);
Онови браузер.
Натисни кнопку.
Тепер товари зʼявляються на сторінці.
Що сталося?
JavaScript:
- завантажив
products.json; - перетворив його в JavaScript-дані;
- пройшовся по товарах циклом;
- створив елементи
<li>; - додав їх на сторінку.
Це frontend development.
Дані приходять.
DOM оновлюється.
Користувач бачить контент.
Красиво.
Трохи драматично.
Але красиво.
Додай Статус Доступності
Тепер покажемо, чи товар доступний.
Заміни цей рядок:
listItem.textContent = `${product.name} - €${product.price}`;
на цей:
const status = product.available ? "Доступний" : "Недоступний";
listItem.textContent = `${product.name} - €${product.price} - ${status}`;
Повний цикл:
for (const product of products) {
const listItem = document.createElement("li");
const status = product.available ? "Доступний" : "Недоступний";
listItem.textContent = `${product.name} - €${product.price} - ${status}`;
productListElement.appendChild(listItem);
}
Це використовує ternary operator.
Він означає:
Якщо product.available true, використовуй "Доступний".
Інакше використовуй "Недоступний".
Коротко.
Корисно.
На початку трохи підозріло.
Але після практики дружньо.
Додай Loading State
Завантаження даних займає час.
Тому варто показати повідомлення про завантаження.
Онови loadProducts:
async function loadProducts() {
messageElement.textContent = "Завантаження товарів...";
productListElement.innerHTML = "";
const response = await fetch("products.json");
const products = await response.json();
for (const product of products) {
const listItem = document.createElement("li");
const status = product.available ? "Доступний" : "Недоступний";
listItem.textContent = `${product.name} - €${product.price} - ${status}`;
productListElement.appendChild(listItem);
}
messageElement.textContent = `Завантажено товарів: ${products.length}.`;
}
Тепер після кліку сторінка каже:
Завантаження товарів...
Це хороший user experience.
Користувачі люблять знати, що щось відбувається.
Інакше вони клікають знову.
І знову.
І знову.
Потім твій застосунок отримує 47 запитів і починає плакати.
Обробка Помилок через try і catch
Іноді fetch не вдається.
Можливо, неправильна назва файлу.
Можливо, сервер не запущено.
Можливо, інтернет має філософську кризу.
Нам потрібно обробляти помилки.
Онови script.js:
const loadButton = document.getElementById("loadButton");
const messageElement = document.getElementById("message");
const productListElement = document.getElementById("productList");
async function loadProducts() {
messageElement.textContent = "Завантаження товарів...";
productListElement.innerHTML = "";
try {
const response = await fetch("products.json");
const products = await response.json();
for (const product of products) {
const listItem = document.createElement("li");
const status = product.available ? "Доступний" : "Недоступний";
listItem.textContent = `${product.name} - €${product.price} - ${status}`;
productListElement.appendChild(listItem);
}
messageElement.textContent = `Завантажено товарів: ${products.length}.`;
} catch (error) {
messageElement.textContent = "Не вдалося завантажити товари.";
console.log(error);
}
}
loadButton.addEventListener("click", loadProducts);
Тепер помилки не руйнують атмосферу мовчки.
Якщо щось піде не так, користувач побачить повідомлення.
А розробник побачить помилку в консолі.
Усі отримують інформацію.
Дуже здорово.
Дуже рідко.
Перевірка response.ok
Є ще один важливий момент.
fetch() не завжди кидає помилку при поганих HTTP-відповідях.
Наприклад, якщо файл не існує, сервер може повернути 404.
Тому варто перевірити:
if (!response.ok) {
throw new Error("Не вдалося завантажити товари.");
}
Онови частину з fetch:
const response = await fetch("products.json");
if (!response.ok) {
throw new Error("Не вдалося завантажити товари.");
}
const products = await response.json();
Повна функція:
async function loadProducts() {
messageElement.textContent = "Завантаження товарів...";
productListElement.innerHTML = "";
try {
const response = await fetch("products.json");
if (!response.ok) {
throw new Error("Не вдалося завантажити товари.");
}
const products = await response.json();
for (const product of products) {
const listItem = document.createElement("li");
const status = product.available ? "Доступний" : "Недоступний";
listItem.textContent = `${product.name} - €${product.price} - ${status}`;
productListElement.appendChild(listItem);
}
messageElement.textContent = `Завантажено товарів: ${products.length}.`;
} catch (error) {
messageElement.textContent = "Не вдалося завантажити товари.";
console.log(error);
}
}
Тепер код сильніший.
Не безсмертний.
Але сильніший.
Як кава після другої чашки.
Додай Кращі Стилі
Зробімо сторінку красивішою.
Онови index.html:
<!DOCTYPE html>
<html lang="uk">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fetch API</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 60px auto;
padding: 0 24px;
background-color: #f3f4f6;
color: #111827;
}
.card {
background-color: white;
padding: 24px;
border: 2px solid #e5e7eb;
border-radius: 18px;
}
h1 {
font-size: 42px;
}
button {
background-color: #2563eb;
color: white;
border: none;
padding: 14px 20px;
border-radius: 999px;
font-weight: 700;
cursor: pointer;
}
button:hover {
background-color: #1d4ed8;
}
.message {
margin-top: 20px;
font-size: 18px;
font-weight: 700;
}
.products {
list-style: none;
padding: 0;
margin-top: 20px;
display: grid;
gap: 12px;
}
.product {
padding: 16px;
border: 2px solid #e5e7eb;
border-radius: 14px;
background-color: #f9fafb;
}
.product strong {
display: block;
font-size: 22px;
margin-bottom: 6px;
}
.available {
color: #166534;
font-weight: 700;
}
.unavailable {
color: #991b1b;
font-weight: 700;
}
</style>
</head>
<body>
<h1>Fetch API</h1>
<div class="card">
<button id="loadButton">Завантажити Товари</button>
<p id="message" class="message">Натисни кнопку, щоб завантажити товари.</p>
<ul id="productList" class="products"></ul>
</div>
<script src="script.js"></script>
</body>
</html>
Тепер онови показ товарів у script.js:
for (const product of products) {
const listItem = document.createElement("li");
const status = product.available ? "Доступний" : "Недоступний";
const statusClass = product.available ? "available" : "unavailable";
listItem.className = "product";
listItem.innerHTML = `
<strong>${product.name}</strong>
<span>Ціна: €${product.price}</span><br>
<span class="${statusClass}">${status}</span>
`;
productListElement.appendChild(listItem);
}
Тепер товари виглядають як картки.
Набагато краще.
Менше “сирий HTML з печери.”
Більше “маленький frontend-застосунок для початківців.”
Прогрес.
Повний JavaScript Код
Ось повний script.js:
const loadButton = document.getElementById("loadButton");
const messageElement = document.getElementById("message");
const productListElement = document.getElementById("productList");
async function loadProducts() {
messageElement.textContent = "Завантаження товарів...";
productListElement.innerHTML = "";
try {
const response = await fetch("products.json");
if (!response.ok) {
throw new Error("Не вдалося завантажити товари.");
}
const products = await response.json();
for (const product of products) {
const listItem = document.createElement("li");
const status = product.available ? "Доступний" : "Недоступний";
const statusClass = product.available ? "available" : "unavailable";
listItem.className = "product";
listItem.innerHTML = `
<strong>${product.name}</strong>
<span>Ціна: €${product.price}</span><br>
<span class="${statusClass}">${status}</span>
`;
productListElement.appendChild(listItem);
}
messageElement.textContent = `Завантажено товарів: ${products.length}.`;
} catch (error) {
messageElement.textContent = "Не вдалося завантажити товари.";
console.log(error);
}
}
loadButton.addEventListener("click", loadProducts);
Тепер у тебе є:
- JSON-файл;
- сторінка;
- fetch-запит;
- loading state;
- обробка помилок;
- рендеринг у DOM.
Це вже серйозний beginner-проєкт.
Маленький.
Але серйозний.
Як маленьке espresso.
Типові Помилки
Відкривати index.html Напряму
Неправильно:
file:///home/user/javascript-lesson11/index.html
Краще:
caddy file-server --listen :8080
Потім відкрий:
http://localhost:8080
Fetch часто потребує сервер.
Навіть маленький локальний.
Не бийся з браузером.
У нього правила.
Багато правил.
Забути await
Неправильно:
const response = fetch("products.json");
const products = response.json();
Правильно:
const response = await fetch("products.json");
const products = await response.json();
Без await у тебе ще немає даних.
У тебе є promise.
Promise — це не результат.
Це майбутній результат.
Як замовлення піци.
Чек — це не піца.
Знову піца.
Але працює.
Забути response.json()
Неправильно:
const products = await response;
Правильно:
const products = await response.json();
Response — це не фінальні дані.
Треба перетворити його в JSON.
JavaScript потужний.
Але йому все одно потрібні інструкції.
Неправильний Шлях до Файлу
Якщо файл називається:
products.json
тоді fetch:
fetch("products.json")
Якщо файл у папці:
data/products.json
тоді fetch:
fetch("data/products.json")
Шляхи мають збігатися.
JavaScript не буде шукати по папках як детектив.
Він просто впаде.
Тихо.
Як кіт, який скидає щось зі столу.
Практика
Створи новий JSON-файл з назвою students.json.
Додай це:
[
{
"name": "Anna",
"level": "Beginner"
},
{
"name": "Marco",
"level": "Intermediate"
},
{
"name": "Viktor",
"level": "Beginner"
}
]
Створи кнопку, яка завантажує студентів.
Покажи кожного студента на сторінці.
Приклад результату:
Anna - Beginner
Marco - Intermediate
Viktor - Beginner
Бонус:
Покажи, скільки студентів було завантажено.
Дуже схоже на товари.
Інші дані.
Та сама схема.
Так працює програмування.
Вивчи один шаблон.
Використовуй його всюди.
Роби вигляд, що було складно.
Дуже професійно.
Мінічелендж
Створи маленький каталог курсів.
Створи courses.json з:
- назвою курсу;
- категорією;
- ціною;
- статусом доступності.
Потім використай fetch(), щоб завантажити курси й показати їх як картки.
Кожна картка має показувати:
- назву;
- категорію;
- ціну;
- доступність.
Бонус:
Показуй тільки доступні курси.
Це означає, що можна використати:
if (course.available) {
// show course
}
Цей челендж поєднує:
- масиви;
- обʼєкти;
- DOM;
- умови;
- fetch;
- JSON.
Коротко кажучи, JavaScript стає маленькою фабрикою вебзастосунків.
Вітаю.
І ще: обережно.
Фабрикам потрібна організація.
Підсумок
Сьогодні ти вивчив:
fetch()завантажує дані з файлів або API;- fetch асинхронний;
asyncдозволяє функції використовуватиawait;awaitчекає на асинхронні результати;- JSON — популярний формат даних;
response.json()перетворює response у JavaScript-дані;- loading-повідомлення покращують user experience;
tryіcatchобробляють помилки;response.okдопомагає виявляти невдалі запити;- завантажені дані можна показувати в DOM;
- локальні сервери допомагають уникнути проблем з локальними файлами.
Це величезний крок.
Твій JavaScript тепер може говорити із зовнішніми даними.
Не тільки зі змінними.
Не тільки з local storage.
Справжні файли.
Потім API.
Потім сервери.
Зовнішній світ.
JavaScript відкрив вікно.
Сподіваюсь, не неправильне.
Наступна Лекція
У наступній лекції ми створимо маленький фінальний проєкт.
Ми поєднаємо:
- змінні;
- масиви;
- обʼєкти;
- функції;
- DOM;
- події;
- форми;
- валідацію;
- local storage;
- fetch.
Справжній JavaScript-проєкт для початківців.
Не величезний.
Не страшний.
Але повний.
Final boss наближається.
Принеси каву.