До недавнего времени отправить или получить данные с сервера можно было с помощью форм с перезагрузкой страницы или с помощью AJAX без перезагрузки. Стандарт ES6 (EcmaScript2015) добавил технологию Fetch API, которая основана на промисах (Promises). Рассмотрим простой вариант получения данных с помощью Fetch API.
Что такое Fetch API?
В переводе с английского “fetch” – это получать, доставать, приносить. Т.е. Fetch API – это простой интерфейс для получения данных с ресурсов. Fetch позволяет нам сделать сетевой запрос и обрабатывать ответы проще, чем наш старый друг XMLHttpRequest (XHR). Одно из основных отличий заключается в том, что Fetch API использует промисы (Promises), что обеспечивает способ избежать большого количества обратных вызовов (так называемый callback hell) и типичного тяжелого кода, который предоставляет XMLHttpRequest (XHR).
Функция fetch()
принимает один обязательный аргумент – путь к ресурсу, который вы хотите получить, и возвращает Promise, который разрешается в ответе (response) этого запроса.
Теперь мы сталкиваемся с новым вопросом – а что такое промисы (Promises, или обещания)?
Что такое промисы?
Объект Promise представляет возможное завершение (или сбой) асинхронной операции и ее результирующее значение.
Промисы (Promises) в JavaScript. Промисы, или обещания предоставляют нам более простую альтернативу выполнению, составлению и управлению асинхронной операцией по сравнению с традиционным подходом на основе обратных вызовов.
Работая с промисами-обещаниями, мы должны знать, каково его текущее состояние, т.к. у этого объекта есть три состояния: Ожидание (Pending), Выполнено (Fulfilled ) и Отклонено (Rejected).
Когда Промис-Обещание находится в состоянии ожидания, оно может перейти в состояние Выполнено или Отклонено. Как только Обещание переходит в состояние Выполнено или Отклонено, оно не может перейти в любое другое состояние и его значение также не изменится (!).
Когда Обещание выполнено, это означает, что асинхронная операция завершена, и Обещание имеет значение. Когда Обещание отклонено, это означает, что асинхронная операция не удалась, и Обещание никогда не будет выполнено.
Использование Fetch API и Promis-ов
Теперь мы будем работать над простым примером, в котором мы будем использовать Fetch API и промисы, чтобы отобразить список, содержащий данные, загружаемые с удаленного ресурса. В качестве такого ресурса будем использовать общедоступный API с информацией различных фильмах под названием The Movie Database API (https://developers.themoviedb.org/3/getting-started/introduction). Для того чтобы ваш код работал, необходимо получить ключ (API Key), зарегистрировавшись в системе.
Поскольку фильмов в этой системе собрано очень много, будем искать фильмы по ключевому “Secret”. API возвращает JSON-файл с данными о 10 фильмах.
Запишем такой код:
1
2
3
4
|
const fetchPromise = fetch(“https://www.omdbapi.com/?apikey=your_api_key&s=secret”);
fetchPromise.then(response => {
console.log(response);
});
|
Когда HTTP-запрос выполняется как асинхронная операция, выборка не возвращает никаких данных. Однако он вернет ответное Обещание (Promise). Когда мы регистрируем ответ, он покажет, что это Обещание находится в состоянии ожидания. Это означает, что ответ HTTP, который мы ожидаем, в конце концов вернется, но на момент регистрации этот ответ не был готов к регистрации.
Изначально наше Обещание (Promis) находится в состоянии ожидания, но через некоторое время оно может перейти в выполненное состояние, если все идет хорошо, или в отклоненное состояние, если при загрузке произошла ошибка. Как только Обещание выполнено, оно больше не может изменять состояние.
Мы регистрируем ответ, чтобы увидеть, какую информацию мы получаем от API с помощью метода Promise.prototype.then(). В консоли браузера мы увидим объект Response (Ответ) с некоторой информацией, которая включает заголовки, текст, тип и даже код состояния.
Поскольку в объекте Response свойство status
имеет значение 200, а statusText
вернуло значение “” или “OK”, можно сделать вывод, что наш объект Promise перешел из состояния Pending (ожидание) в состояние Fulfilled (выполнено). Двигаемся дальше и пробуем извлечь данные о фильмах из ответа (response) нашего объекта Promise. Мы опять будем использовать метод промиса then()
, чтобы прикрепить обратный вызов, как только наше обещание будет выполнено.
Для того чтобы получить тело ответа в формате JSON, используем метод json()
для ответа вместо console.log()
. Эта операция также является асинхронной. Имейте ввиду, что метод json()
возвращает еще один Promise, поэтому нам нужно создать цепочку Обещаний с помощью такого кода:
1
2
3
4
5
6
|
const fetchPromise = fetch(“https://www.omdbapi.com/?apikey=your_api_key&s=secret”);
fetchPromise.then(response => {
return response.json();
}).then(films => {
console.log(films);
});
|
Мы передадим значение, полученное от первого Promise, в нашу цепочку, чтобы вывести информацию об искомых фильмах в консоль. Поскольку мы выполняли поиск по базе данных, то нам вернется массив Search из 10 фильмов, и каждый фильм имеет свой imdbID, Title и Poster и Year, которые мы будем выводить на странице. Кроме того, мы также сразу видим, сколько фильмов имеет такое слово в своем названии, в totalResults.
Вот что видно в консоли (скриншот):
Вывод информации на html-страницу
Теперь нам просто нужно сформировать красивый html на основе полученной информации. Используем для форматирования вывода информации о фильмах компонент Card (Карточка) Bootstrap-4. Для разметки нам понадобится основной <div id="films">
и вложенные в него элементы <div class="container">
и <div class="row">
. Код видоизменится таким образом:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
<div id=“films”>
<div class=“container”>
<h1 class=“text-center my-4”>Movies with the title “Secret”</h1>
<div class=“row row-cols-lg-4 row-cols-md-3 row-cols-sm-2”></div>
</div>
</div>
<script>
const fetchPromise = fetch(“https://www.omdbapi.com/?apikey=your_api_key&s=secret”);
let mainContent = ”,
main = document.querySelector(‘#films .row’);
fetchPromise.then(response => {
return response.json();
}).then(films => {
// console.log(films.Search); //вывод данных запроса
films.Search.forEach((film, index) => {
mainContent+=`
<div class=“movie mb-3”>
<div class=“card border-success shadow” id=“${film.imdbID}”>
<img class=“card-img-top” src=“${film.Poster}” alt=“${film.Title}”>
<div class=“card-header bg-success text-light”>
<div class=“card-title”>
<h5 class=“card-title”>${film.Title}</h5>
</div>
</div>
<div class=”card-body” data-id=”${film.id}”>
<p class=”card-text”><strong>Release Date:</strong> ${film.Year}</p>
</div>
</div>
</div>`;
});
</script>
|
Результат можно посмотреть ниже или в новой вкладке:
Fetch API предоставил нам возможность загрузить данные достаточно быстро и с формированием структуры html-страницы на основе полученных JSON-данных. Этой технологией можно пользоваться в тех браузерах, которые поддерживают новые JS стандарты.
На основе статьи How to make HTTP requests using Fetch API and Promises