Рано или поздно JavaScript перестает жить только внутри страницы. Хочется нажать кнопку и получить данные с сервера: список постов, цену товара, погоду, курс валют, статус заказа
Раньше такие запросы часто называли AJAX. Сейчас в обычном браузерном JavaScript для этого чаще используют fetch. А fetch возвращает Promise, потому что ответ от сервера приходит не мгновенно
В этом уроке сделаем первый запрос к API, покажем loading, обработаем ошибку и выведем данные на страницу
- Что получится в конце
- Что такое Promise простыми словами
- Что делает fetch
- Делаем HTML
- Первый fetch по клику
- Почему HTTP-ошибка не всегда попадает в catch
- Версия с обработкой ошибки на странице
- async/await
- AJAX и fetch — это одно и то же?
- CORS: почему запрос может быть заблокирован
- Частые ошибки
- Забыли return response.json()
- Не обработали ошибку
- Думают, что fetch сразу возвращает данные
- Используют await не внутри async
- Мини-задание
- Ответы на эти вопросы могут быть для вас полезными
- Что такое Promise в JavaScript?
- Что такое AJAX?
- Что возвращает fetch?
- Почему fetch не попал в catch при 404?
- Что лучше: then или async/await?
- Что почитать дальше по JavaScript
Что получится в конце
Мы соберем кнопку "Загрузить пост" и блок результата:
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then((response) => response.json())
.then((post) => {
console.log(post.title);
});
Потом перепишем на async/await, потому что так код часто читается проще
Что такое Promise простыми словами
Promise — это объект, который представляет будущий результат асинхронной операции
Состояния:
- pending — операция еще идет;
- fulfilled — операция завершилась успешно;
- rejected — операция завершилась ошибкой.
MDN описывает Promise как объект, который представляет eventual completion или failure асинхронной операции и ее значение. Для практики запомним проще: Promise — это обещание результата позже
Пример без сети:
const promise = new Promise((resolve) => {
setTimeout(() => {
resolve("Данные готовы");
}, 1000);
});
promise.then((message) => {
console.log(message);
});
Код не блокирует страницу. Он говорит: когда данные будут готовы, выполни функцию в then
Что делает fetch
fetch() делает сетевой запрос. По документации Fetch API метод fetch доступен в браузерном контексте и возвращает Promise с объектом Response
Минимальный пример:
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then((response) => response.json())
.then((post) => {
console.log(post);
});
Здесь два асинхронных шага:
- Дождаться ответа сервера.
- Прочитать тело ответа как JSON.
Поэтому response.json() тоже возвращает Promise
Делаем HTML
<button class="load-post">Загрузить пост</button>
<p class="status">Нажмите кнопку</p>
<article class="post"></article>
Первый fetch по клику
const loadButton = document.querySelector(".load-post");
const status = document.querySelector(".status");
const postContainer = document.querySelector(".post");
loadButton.addEventListener("click", () => {
status.textContent = "Загружаем...";
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then((response) => response.json())
.then((post) => {
status.textContent = "Готово";
postContainer.innerHTML = `
<h2>${post.title}</h2>
<p>${post.body}</p>
`;
});
});
Теперь кнопка делает запрос и выводит данные
Почему HTTP-ошибка не всегда попадает в catch
У fetch есть важный нюанс: если сервер ответил статусом 404 или 500, сам Promise может считаться выполненным, потому что ответ от сервера получен. Нужно проверять response.ok
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then((response) => {
if (!response.ok) {
throw new Error("Ошибка сервера");
}
return response.json();
})
.then((post) => {
console.log(post);
})
.catch((error) => {
console.log(error.message);
});
catch поймает сетевую ошибку или ошибку, которую мы сами выбросили через throw
Версия с обработкой ошибки на странице
loadButton.addEventListener("click", () => {
status.textContent = "Загружаем...";
postContainer.innerHTML = "";
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then((response) => {
if (!response.ok) {
throw new Error("Сервер вернул ошибку");
}
return response.json();
})
.then((post) => {
status.textContent = "Готово";
postContainer.innerHTML = `
<h2>${post.title}</h2>
<p>${post.body}</p>
`;
})
.catch((error) => {
status.textContent = "Не получилось загрузить данные";
postContainer.textContent = error.message;
});
});
Это уже нормальная схема для интерфейса:
- перед запросом показываем loading;
- при успехе выводим данные;
- при ошибке показываем понятное сообщение.
async/await
Тот же код можно написать так:
loadButton.addEventListener("click", async () => {
status.textContent = "Загружаем...";
postContainer.innerHTML = "";
try {
const response = await fetch("https://jsonplaceholder.typicode.com/posts/1");
if (!response.ok) {
throw new Error("Сервер вернул ошибку");
}
const post = await response.json();
status.textContent = "Готово";
postContainer.innerHTML = `
<h2>${post.title}</h2>
<p>${post.body}</p>
`;
} catch (error) {
status.textContent = "Не получилось загрузить данные";
postContainer.textContent = error.message;
}
});
await можно читать как "подожди результат Promise". Но использовать его можно внутри async-функции
AJAX и fetch — это одно и то же?
Не совсем. AJAX — более старое общее название подхода: страница общается с сервером без полной перезагрузки. Раньше часто использовали XMLHttpRequest. Сейчас для многих задач используют fetch
Если пользователь ищет javascript promise ajax example, ему обычно нужен современный пример: кнопка, запрос, JSON, loading, ошибка. Поэтому fetch — хороший вход
CORS: почему запрос может быть заблокирован
Иногда код правильный, но браузер пишет ошибку CORS. Это значит, что сервер не разрешил странице с твоего домена читать ответ
Примерно:
Access to fetch at ... has been blocked by CORS policy
Это не лечится простым изменением JavaScript на клиенте. Нужно:
- использовать API, которое разрешает такие запросы;
- настроить CORS на своем сервере;
- делать запрос через свой backend;
- не пытаться читать чужой сайт как API.
Частые ошибки
Забыли return response.json()
Неправильно:
fetch(url)
.then((response) => {
response.json();
})
.then((data) => {
console.log(data);
});
Во второй then придет undefined
Правильно:
fetch(url)
.then((response) => response.json())
.then((data) => {
console.log(data);
});
Не обработали ошибку
Без catch пользователь может просто увидеть тишину. В интерфейсе всегда лучше показать понятное состояние
Думают, что fetch сразу возвращает данные
const data = fetch(url);
data будет Promise, а не готовые данные. Нужен then или await
Используют await не внутри async
const response = await fetch(url);
Так можно только внутри async-функции или в окружении, где разрешен top-level await
Мини-задание
Сделай загрузку списка постов:
const response = await fetch("https://jsonplaceholder.typicode.com/posts?_limit=5");
const posts = await response.json();
Выведи каждый пост:
postContainer.innerHTML = posts
.map((post) => `<h2>${post.title}</h2><p>${post.body}</p>`)
.join("");
Добавь:
- состояние "Загружаем…";
- обработку ошибки;
- очистку старого результата перед новым запросом.
Ответы на эти вопросы могут быть для вас полезными
Что такое Promise в JavaScript?
Это объект, который представляет будущий результат асинхронной операции: успешный ответ или ошибку
Что такое AJAX?
Это подход, когда страница получает данные с сервера без полной перезагрузки. Сейчас часто используют fetch
Что возвращает fetch?
fetch возвращает Promise с объектом Response. Чтобы получить JSON, нужно вызвать response.json()
Почему fetch не попал в catch при 404?
Потому что HTTP-ответ был получен. Нужно вручную проверить response.ok и выбросить ошибку, если статус плохой
Что лучше: then или async/await?
Оба варианта рабочие. async/await часто легче читать, но полезно понимать и цепочку then
Что почитать дальше по JavaScript
Чтобы двигаться по теме без рывков, рядом лучше открыть:
- События и клики в JavaScript: addEventListener без путаницы — запускать запросы по клику или отправке формы.
- If else в JavaScript: условия на живых примерах — проверять
response.ok, ошибки и разные состояния ответа. - JavaScript online compiler: как попробовать код без установки — понять, почему для запросов часто нужен реальный браузерный пример.
- ООП в JavaScript без академического тумана — лучше читать объекты, которые приходят из JSON.



