img

Промис (Promise) в JavaScript

Промис в JavaScript — это заменитель (прокси) для значения текущей операции. Обычно мы используем промис для управления ситуациями, когда необходимо дождаться результата операции. Например, при загрузке файлов на сервер и ожидании ответа от API, или просто при запросе у пользователя выбора файла с их компьютера.

В этой статье вы узнаете о промисах в JavaScript, создавая реальное приложение, похожее на приведенное ниже:

Что такое промис? 

Промис — это просто функция, она возвращает объект, к которому можно прикрепить обратные вызовы.

Обратные вызовы, прикрепленные к объекту промиса, будут вызываться только после завершения операции. Обратные вызовы будут ожидать, пока операция не будет выполнена или отклонена.

fetch(`some_api_url`).then((response) => {
  // Everything here will wait the fetch operation to complete
});

Прежде чем промис окончательно решится (то есть либо выполнится, либо будет отклонен), он должен пройти через разные состояния:

Состояние

Описание

Обратный вызов

Ожидание

Операция все еще выполняется, и промис находится в ожидании

-

Выполнен

Операция завершена успешно

.then()

Отклонен

Операция завершена с ошибкой

.catch()

Завершен

Промис либо разрешен, либо отклонен, в любом случае вызывается этот обратный вызов

.finally()

Когда создается промис, начальное состояние — ожидание. Затем, в зависимости от результата операции, промис либо выполняется, либо отклоняется.

Из таблицы выше можно легко увидеть обратный вызов, который будет вызван в зависимости от состояния промиса:

fetch(`some_api_url`).then((response) => {
  // This will get called when the promise fulfills
}).catch((error) => {
  // This will get called when the promise is rejected
}).finally(() => {
  // This will get called all the time
})

Как использовать промисы в JavaScript

Теперь, когда вы узнали, что такое промис, давайте покажем, как вы можете использовать промисы в JavaScript, создав приложение для поиска фильмов, которое мы видели ранее.

Базовое приложение для поиска фильмов должно иметь поле ввода, где пользователи могут искать свои любимые фильмы. Также должно быть пользовательский интерфейс для отображения базовой информации о найденном фильме.

Давайте начнем с создания HTML.

Как написать HTML

Для целей этого руководства и чтобы показать живые примеры, я буду использовать Codepen, но вы можете использовать ваш любимый редактор кода.

Создайте файл index.html и добавьте следующий код:

<div class="wrapper">
      <header class="header">
        <div class="header_logo">Movie</div>
        <div class="header_actions">
          <form onsubmit="handle_form(event)" id="header_form">
            <div class="header_form-icon">
            <input type="search" class="header_form-input" placeholder="Search, Press Enter to Submit" />
            <svg class="icon" width="22px" height="22px"><use href="#icon-search" /></svg>
          </div>
          </form>
          <img id="img_icon" width="32px" height="32px" src="" alt="" >
        </div>
      </header>
      <main id="main">
        <section>
          <article class="movie">
            <div class="movie_img">
              <img id="img_src" src="" alt="" srcset="">
            </div>
            <div class="movie_info">
              <header><h1 class="movie_title"></h1></header>
              <div class="movie_desc"></div>
              <div class="movie_details">
                <h2>Details</h2>
                <ul class="flex">
                  <li>Premiered: <span id="movie_date"></span></li>
                  <li>Rating: <span id="movie_rating"></span></li>
                  <li>Runtime: <span id="movie_runtime"></span></li>
                  <li>Status: <span id="movie_status"></span></li>
                </ul>
              </div>
              <a href="" class="btn" target="_blank" rel="noopener noreferrer">
            <svg class="icon" width="16px" height="16px"><use href="#icon-play" /></svg>
                Watch Movie</a>
            </div>
          </article>
          <div class="episodes_list">
            <h3 class="episodes_title"></h3>
          <ol class="episodes" id="episodes"></ol>
        </div>
        </section>
      </main>
    </div>

Мы создали скелет нашего приложения для фильмов. Теперь давайте оживим его с помощью CSS:

%[https://codepen.io/Spruce_khalifa/pen/wvygzLq?editors=0100]

Как получить фильм

Чтобы получить наш фильм, мы будем использовать API TVMAZE. Создайте файл main.js и добавьте следующий код:

const get_movie = (value = "Game of thrones") => {
   fetch(
    `https://api.tvmaze.com/singlesearch/shows?q=${value}&embed=episodes`
  ).then((response) => create_UI(response.json()));
};

Мы создали функцию get_movie(value = "Game of thrones"), которая использует API fetch в JavaScript. Мы используем его для выполнения GET запроса к нашему API фильмов.

API fetch возвращает промис. Чтобы использовать ответ от API, мы прикрепляем обратный вызов .then(), в который передаем response.json() в новую функцию create_UI(). Давайте создадим функцию create_UI:

const create_UI = (data) => {
  const movie_img = document.querySelector("#img_src");
  const movie_icon = document.querySelector("#img_icon");
  const movie_title = document.querySelector(".movie_title");
  const movie_desc = document.querySelector(".movie_desc");
  const movie_link = document.querySelector(".btn");
  const movie_date = document.querySelector("#movie_date");
  const movie_rating = document.querySelector("#movie_rating");
  const movie_runtime = document.querySelector("#movie_runtime");
  const movie_status = document.querySelector("#movie_status");

  // set the UI
  movie_icon.src = data.image.medium;
  movie_img.src = data.image.original;
  movie_title.textContent = data.name;
  movie_desc.innerHTML = data.summary;
  movie_link.href = data.officialSite;
  movie_date.textContent = data.premiered;
  movie_rating.textContent = data.rating.average;
  movie_runtime.textContent = data.runtime;
  movie_status.textContent = data.status;
};

Эта функция, как следует из названия, помогает нам создать пользовательский интерфейс для нашего приложения фильмов. Но нам все еще нужен способ получить имя фильма от пользователей, так что давайте это исправим.

Первое, что нам нужно сделать, это добавить обработчик события onsubmit в нашу HTML-форму:

<form onsubmit="search(event)" id="header_form">
  <input type="search" class="header_form-input" placeholder="Search, Press Enter to Submit" />
//
</form>

Теперь в нашем файле main.js мы можем обработать то, что происходит при отправке формы:

// handle form submit
const search = (event) => {
  event.preventDefault();
  const value = document.querySelector(".header_form-input").value;

  get_movie(value);
};

Каждый раз, когда пользователь отправляет форму, мы получаем значение, которое они ввели в поле поиска, и передаем его в функцию get_movie(value = "Game of thrones"), которую мы создали ранее.

Цепочка промисов

В отличие от того, что мы видели в предыдущих примерах, обратный вызов .then() не является концом. Дело в том, что когда вы возвращаете значение промиса, вы получаете другой промис. Это становится очень полезным, когда вы хотите выполнить серию асинхронных операций по порядку.

Например, наше API фильмов не только возвращает информацию о фильме, но и информацию обо всех эпизодах. Допустим, что мы действительно не хотим отображать все эпизоды "Игры престолов", нам нужны только первые четыре (4) эпизода.

С помощью цепочки промисов мы можем легко этого достичь:

const get_movie = (value = "Game of thrones") => {
  fetch(`https://api.tvmaze.com/singlesearch/shows?q=${value}&embed=episodes`)
    .then((response) => response.json())
    .then((data) => {
      if (data._embedded.episodes.length > 0) {
        const new_data = data._embedded.episodes.slice(0, 4);

        create_UI(data);
        return create_episodesUI(new_data);
      } else {
        return create_UI(data);
      }
    });
};

Это все та же функция get_movie(), но на этот раз, вместо того чтобы передавать данные в функцию create_UI, мы возвращаем ответ .then((response) => response.json()). Это создает новый промис, к которому мы можем прикрепить дополнительные обратные вызовы.

В идеале эта цепочка может продолжаться бесконечно. Помните, что все, что вам нужно сделать, это вернуть значение промиса.

Как обрабатывать ошибки в промисах

Ошибки, которые происходят в промисе, немедленно попадают в обратный вызов .catch():

fetch(`https://api.tvmaze.com/singlesearch/shows?q=${value}&embed=episodes`)
    .then((response) => response.json())
    .then((data) => {
      // any error here will trigger the .catch() callback
    }).catch((error) => {
    // all errors are caught and handled here
    })

Обратный вызов .catch() является сокращением для .then(null, (error) => {}). Вы также можете написать это так:

fetch(`https://api.tvmaze.com/singlesearch/shows?q=${value}&embed=episodes`)
    .then((response) => response.json())
    .then((data) => {
      // any error here will trigger the .catch() callback
    }, (error) => {
    // all errors are caught and handled here
    })

В нашем приложении для поиска фильмов, например, когда мы сталкиваемся с ошибками, мы можем обработать и отобразить пользователям приятное сообщение об ошибке в обратном вызове .catch():

const get_movie = (value = "Game of thrones") => {
  fetch(`https://api.tvmaze.com/singlesearch/shows?q=${value}&embed=episodes`)
    .then((response) => response.json())
    .then((data) => {
      if (data._embedded.episodes.length > 0) {
        const new_data = data._embedded.episodes.slice(0, 4);

        create_UI(data);
        return create_episodesUI(new_data);
      } else {
        return create_UI(data);
      }
    })
    .catch((error) => {
      console.log(error.message);
      // Challange: display your error here
    });
};

Теперь, если по какой-то причине мы получаем ошибку, обратный вызов .catch() будет вызван, и мы отобразим корректную ошибку пользователю.

Как создать промисы в JavaScript

Теперь, когда мы узнали, что такое промисы и как их использовать, давайте посмотрим, как мы можем создать промис в JavaScript.

Чтобы создать промис в JavaScript, используйте конструктор промиса. Конструктор принимает один аргумент: функцию с двумя параметрами, resolve и reject:

const is_true = true
const new_promise = new Promise((resolve,reject) => {
  if(is_true) {
    // everything went fine
    resolve()
  } else {
    // Oops there was an error
    reject()
  }
})

Затем мы можем использовать наш new_promise, прикрепляя к нему обратные вызовы:

new_promise
  .then((response) => {
    // everything went fine
  })
  .catch((error) => {
    // handle errors
  });

Подведем итоги

В этом руководстве мы узнали о промисах, что это такое и как их использовать, создавая приложение для поиска.

Счастливого кодинга!

Ссылка
скопирована
Получите бесплатные уроки на наших курсах
Все курсы
Программирование
Скидка 25%
Фронтенд-разработчик с нуля
Погрузитесь в мир веб-разработки, освоив основные инструменты работы: HTML, CSS, JavaScript. Научитесь работать с дизайн-макетами и адаптивной версткой, сверстаете свои первые страницы и поймете, как строить карьерный трек в ИТ.
Получи бесплатный
вводный урок!
Пожалуйста, укажите корректный e-mail
отправили вводный урок на твой e-mail!
Получи все материалы в telegram и ускорь обучение!
img
Еще по теме:
img
В этой статье обсудим один из важнейших аргументов функции, который ТЫ, мой друг, будешь использовать в каждом своем боте.  Ты с
img
Введение    Настало время глубже погрузиться во взаимодействие человека с ботом. Сегодня изучим декоратор message_handler(). Узн
img
Погружение в aiogram (#5 Отправка стикеров)   Введение   Продолжаем изучать функционал библиотеки aiogram для работы с Telegram
img
Гипервизор - это программное обеспечение для виртуализации, используемое для создания и запуска виртуальных машин (ВМ). Гипервиз
img
Виртуализация серверов позволяет запускать несколько виртуальных машин на одном физическом сервере. Запуск виртуальных машин (ВМ
img
Сегодня мы рассмотрим, как настроить и использовать PHP в проекте. Но прежде чем начать, нужно понять, что такое PHP. Что такое
ЗИМНИЕ СКИДКИ
40%
50%
60%
До конца акции: 30 дней 24 : 59 : 59