Пошук уроків, статей та іншого контенту
Виконання HTTP-запитів у браузері, обробка відповіді та скасування запитів, що більше не потрібні.
fetch — глобальна функція, доступна в браузері й Node.js, що виконує HTTP-запит і повертає Promise (з усіх попередніх уроків цього модуля). Найпростіший виклик — просто URL, за замовчуванням це GET-запит:
async function loadPosts() {
const response = await fetch("https://api.example.com/posts");
const posts = await response.json(); // тіло відповіді теж читається асинхронно, окремим await
return posts;
}Найважливіший нюанс fetch: Promise відхиляється лише при мережевій помилці (немає з'єднання, DNS не резолвиться) — HTTP-статуси на кшталт 404 чи 500 НЕ спричиняють reject. fetch вважає «успішно отримати відповідь із кодом 404» — успіхом самого запиту. Статус потрібно перевіряти вручну:
async function loadPost(id) {
const response = await fetch(`https://api.example.com/posts/${id}`);
if (!response.ok) { // response.ok === true лише для статусів 200-299
throw new Error(`HTTP помилка: ${response.status}`);
}
return response.json();
}async function createPost(title, content) {
const response = await fetch("https://api.example.com/posts", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ title, content }), // JSON.stringify з модуля «DOM та браузер» (localStorage)
});
if (!response.ok) {
throw new Error(`Не вдалось створити пост: ${response.status}`);
}
return response.json();
}async function safeLoadPost(id) {
try {
const response = await fetch(`https://api.example.com/posts/${id}`);
if (!response.ok) {
throw new Error(`Сервер повернув помилку: ${response.status}`);
}
return await response.json();
} catch (error) {
// сюди потрапляє І мережева помилка (немає інтернету), І помилка статусу з рядка вище
console.error("Не вдалось завантажити пост:", error.message);
return null;
}
}Коли запит більше не потрібен (наприклад, користувач перейшов на іншу сторінку чи ввів новий пошуковий запит до завершення попереднього), його варто скасувати, а не просто ігнорувати результат — це звільняє мережеві ресурси й запобігає обробці застарілих даних:
const controller = new AbortController();
fetch("https://api.example.com/search?q=javascript", {
signal: controller.signal, // прив'язуємо запит до контролера
})
.then((response) => response.json())
.catch((error) => {
if (error.name === "AbortError") {
console.log("Запит скасовано");
} else {
console.error("Інша помилка:", error);
}
});
// Десь в іншому місці, наприклад при новому пошуковому запиті:
controller.abort();Поєднання з debounce із модуля «Функції» — типовий патерн для поля живого пошуку, де кожен новий запит має скасовувати попередній, ще не завершений:
let currentController = null;
async function search(query) {
currentController?.abort(); // скасувати попередній незавершений запит, якщо є
currentController = new AbortController();
const response = await fetch(`/api/search?q=${query}`, {
signal: currentController.signal,
});
return response.json();
}Перевірка лише response.ok, забуваючи, що fetch також може відхилитись при мережевій помилці — потрібен try/catch навколо всього, а не лише перевірка статусу.
Забутий Content-Type: application/json у заголовках POST-запиту з JSON-тілом — сервер може не розпізнати формат даних.
Ігнорування застарілих запитів замість AbortController — швидкий ввід у полі пошуку може призвести до того, що відповідь на СТАРИЙ запит прийде ПІЗНІШЕ за відповідь на новий і перезапише актуальний результат.
fetch виконує HTTP-запити й повертає Promise, що відхиляється лише при мережевих помилках — HTTP-статуси (зокрема помилкові) потрібно перевіряти вручну через response.ok. AbortController дозволяє скасувати запит, що більше не потрібен, через спільний signal — важливо для полів живого пошуку та швидкої навігації. Цим завершується огляд асинхронного JavaScript на цій платформі.
Спробуйте самостійно
Напишіть функцію loadWithTimeout(url, ms), яка виконує fetch і автоматично скасовує його через AbortController, якщо відповідь не прийшла за ms мілісекунд. Підказка: поєднайте AbortController із setTimeout.