fetch - стандартный способ делать HTTP-запросы в браузере. Самый частый сценарий - GET-запрос и разбор JSON.
Важно помнить:
fetchвозвращает Promiseresponse.json()тоже возвращает Promisefetchне считает HTTP 404/500 ошибкой автоматически -response.okнужно проверять вручную
1) Самый простой GET + JSON
fetch("/api/data")
.then((response) => response.json())
.then((data) => {
console.log(data);
});
Этот вариант работает, но здесь нет проверки статуса и обработки ошибок.
2) Правильный базовый шаблон: проверка response.ok
fetch("/api/data")
.then((response) => {
if (!response.ok) {
throw new Error("HTTP " + response.status);
}
return response.json();
})
.then((data) => {
console.log(data);
})
.catch((e) => {
console.log(e.message);
});
3) Тот же шаблон через async/await
async function loadJSON(url) {
const response = await fetch(url);
if (!response.ok) {
throw new Error("HTTP " + response.status);
}
return response.json();
}
async function run() {
try {
const data = await loadJSON("/api/data");
console.log(data);
} catch (e) {
console.log(e.message);
}
}
run();
4) Что такое Response: важные свойства
После fetch получается объект Response.
Полезные свойства:
response.ok- true, если статус 200-299response.status- код ответа (200, 404, 500 и т.д.)response.headers- заголовкиresponse.url- итоговый URL
Пример:
async function run() {
const response = await fetch("/api/data");
console.log(response.ok);
console.log(response.status);
console.log(response.url);
}
run();
5) Разбор JSON: что может пойти не так
response.json() выбросит ошибку, если сервер вернул не JSON или вернул битый JSON.
Поэтому правильно:
- сначала проверить response.ok
- затем парсить JSON
- и все это завернуть в обработку ошибок
async function loadJSON(url) {
const response = await fetch(url);
if (!response.ok) {
throw new Error("HTTP " + response.status);
}
const data = await response.json();
return data;
}
6) Query-параметры в GET: URL и URLSearchParams
Если нужно сформировать URL с параметрами, удобно использовать URL и URLSearchParams.
const url = new URL("/api/search", location.origin);
url.searchParams.set("q", "js");
url.searchParams.set("page", "1");
fetch(url)
.then((r) => r.json())
.then((data) => {
console.log(data);
});
7) Таймаут: fetch сам по себе не прерывается
По умолчанию fetch может ждать долго. Для таймаута используют AbortController.
async function fetchWithTimeout(url, ms) {
const controller = new AbortController();
const timerId = setTimeout(() => controller.abort(), ms);
try {
const response = await fetch(url, { signal: controller.signal });
return response;
} finally {
clearTimeout(timerId);
}
}
async function run() {
try {
const response = await fetchWithTimeout("/api/data", 2000);
if (!response.ok) {
throw new Error("HTTP " + response.status);
}
const data = await response.json();
console.log(data);
} catch (e) {
console.log(e.name);
console.log(e.message);
}
}
run();
Если запрос прерван, ошибка обычно будет с name === “AbortError”.
8) Частые ошибки
1) Забыть await у response.json()
async function run() {
const response = await fetch("/api/data");
const data = response.json();
console.log(data);
}
data здесь Promise. Нужно:
async function run() {
const response = await fetch("/api/data");
const data = await response.json();
console.log(data);
}
2) Считать 404 “ошибкой fetch”
fetch("/api/missing")
.then((response) => response.json())
.then((data) => {
console.log(data);
});
Если сервер вернет 404 и не JSON, будет ошибка на json(). Правильнее проверять ok.
Что стоит запомнить
- fetch возвращает Promise с объектом Response.
- HTTP 404/500 не бросают ошибку автоматически - нужно проверять response.ok.
- response.json() тоже асинхронный и возвращает Promise.
- Для query-параметров удобно URLSearchParams.
- Для таймаута подходит AbortController.