Language

JavaScript: учим Promises

Promises в JavaScript – это проще, чем вы думаете. Основы Promises.

Что нового я узнаю?

Данная статья посвящена promises (промисам) в JavaScript. Она не является исчерпывающим руководством, однако в ней представлена информация, которая поможет вам разобраться с основными моментами, необходимыми для начала использования промисов в вашем коде.

Зачем нужны промисы в JavaScript?

С помощью промисов (как, собственно, и callback-функций) одна часть кода выполняется только после того, как была выполнена другая часть.

Зачем вообще нужны промисы? Все очень просто: представьте веб-сайт, который сначала загружает данные от API, затем он обрабатывает полученные данные, форматирует их и отображает пользователю. Так вот, если мы попытаемся обработать и отформатировать такие данные до того как API выберет необходимую информацию, то мы либо получим сообщение об ошибке, либо перед нами откроется пустая веб-страница. Использование промисов гарантирует, что данные, полученные из API, не будут обрабатываться/форматироваться до тех пор, пока вызов API не будет успешно выполнен.

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

В JavaScript «промисы» представляет собой конечный результат выполнения асинхронной операции. Их можно рассматривать в качестве своеобразного «заполнителя». Такой «заполнитель», по существу, является объектом, к которому мы можем привязать функции обратного вызова (колбэки).

Всего существует 3 возможных состояния для промисов:

  • Pending (ожидание) означает, что асинхронная операция выполняется;
  • Fulfilled (успешное выполнение) означает, что операция была выполнена успешно, а промисам было присвоено определенное значение;
  • Rejected (выполнено с ошибкой) означает, что во время выполнения операции произошла ошибка.

В том случае если состояние промиса не находится в ожидании обработки (pending), то промис считается выполненным, при чем выполненным окончательно: его состояние не может меняться.

Начало работы с промисами

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

Например, простой промис может выглядеть подобным образом:

runFunction().then(successFunc, failureFunc);

Из приведенного выше примера видно, что сначала мы вызываем функцию runFunction (). Ввиду того, что runFunction() возвращает промис, то он (промис) будет выполнен только после  того, как одна из возможных функций – либо successFunc, либо failureFunc – будет выполнена. Если же промис был выполнен успешно (fulfilled), то вызывается sucessFunc, а если во время выполнения такого промиса произошла ошибка – вызывается failureFunc.

Пример использования промисов

Давайте рассмотрим на примере, где мы можем использовать наши промисы. Ничего страшного, если сейчас вам покажется, что такой пример не имеет смысла: позже вы все поймете.

function delay(t){
  return new Promise(function(resolve){
    return setTimeout(resolve, t)
  });
}

function logHi(){
  console.log('hi');
}

delay(2000).then(logHi);

Вверху представлены две функции: delay() и logHi(). Функция logHi()  просто выводит на консоль строку ‘hi’. С функцией delay() все немного сложнее: она возвращает промис, выполнение которого будет разрешено после заданного времени. Для регистрации обратных вызовов (колбэков) мы используем метод then (), чтобы получить одно из возможных значений – либо fulfilled, либо rejected.

Учитывая все вышеописанное, в нашей функции запаздывания мы можем применить delay(2000).then(logHi), при этом после 2 секунд (2000 миллисекунд) выполнение нашего промиса будет разрешено и только после этого функция logHi  будет выполнена.

Чтобы лучше понять, как это работает, просто откройте Google Chrome Developer Tools и напишите подобный код!

Чейнинг или цепочки из промисов

Одно из основных преимуществ промисов заключается в том, что мы можем строить цепочки или «чейны» из асинхронных операций. Это значит, что мы можем указать, что выполнение последующих операций будет начато только после успешного выполнения предыдущих операций. Такой метод называется чейнинг (от англ. chaining) промисов. Привожу пример:

new Promise(function(resolve, reject) {
  setTimeout(() => resolve(1), 2000);

}).then((result) => {
  alert(result);
  return result + 2;

}).then((result) => {
  alert(result);
  return result + 2;

}).then((result) => {
  alert(result);
  return result + 2;

});

В приведенном выше примере кода показано, что изначальный промис будет выполнен по прошествии 2000 миллисекунд, при этом его значение будет равно 1. После этого вызывается  then(), а значение “1” выводится на экран. Наконец, первоначальное значение добавляется к значению, равному “2”, и в итоге на экран выводится новое значение – 3. После этого полученное значение переходит к следующему обработчику then(), и весь процесс начинается сызнова.

Как вы уже поняли данный пример навряд ли будет полезен в реальных проектах, однако с его помощью вы лучше поймете принцип объединения промисов в чейны. Такой подход может оказаться очень полезным для определенных задач, выполняемых в JavaScript, например: для загрузки внешних ресурсов или для ожидания данных API перед их обработкой.

Устранение ошибок

Пока что мы с вами рассмотрели только выполнение промисов, однако это не все, что мне хотелось бы вам рассказать. Например, мы можем использовать .catch() для выявления ошибок, которые произошли в цепочке промисов. Давайте рассмотрим, что собой представляет .catch():

// ....
})
.catch((e) => {
  console.log('error: ', e)
}

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

new Promise(function(resolve, reject) {
  setTimeout(() => resolve(1), 2000);

}).then((result) => {
  alert(result);
  return result + 2;

}).then((result) => {
  throw new Error('FAILED HERE');
  alert(result);
  return result + 2;

}).then((result) => {
  alert(result);
  return result + 2;

}).catch((e) => {
  console.log('error: ', e)
});

После выполнения данного кода произойдет следующее:

  • Промис будет выполнен спустя 2 секунды и примет значение “1”.
  • Полученное значение перейдет к следующему .then()и будет выведено на экран. Значение “2” будет добавлено к первому значению, в результате чего мы получим новое значение – “3”, которое перейдет ко второму.then()
  • Будет выявлена ошибка. Выполнение кода будет приостановлено, а промис примет значение «rejected».
  • .catch() получит сообщение о найденной ошибке в значении, и на экране появится соответствующее сообщение.

Выглядеть это будет следующим образом:

Заключение:

Спасибо всем читающим за ваше внимание! Если вы хотели бы узнать про промисы больше, то я подготовил для вас эту, вот эту и еще одну статьи. Я очень надеюсь, что моя статья стала  для вас полезным вводным руководством по применению промисов!

Оригинал.

 

Dr. Michael J. Garbade

I, Dr. Michael J. Garbade is the co-founder of the Education Ecosystem (aka LiveEdu), ex-Amazon, GE, Rebate Networks, Y-combinator. Python, Django, and DevOps Engineer. Serial Entrepreneur. Experienced in raising venture funding. I speak English and German as mother tongues. I have a Masters in Business Administration and Physics, and a Ph.D. in Venture Capital Financing. Currently, I am the Project Lead on the community project -Nationalcoronalvirus Hotline I write subject matter expert technical and business articles in leading blogs like Opensource.com, Dzone.com, Cybrary, Businessinsider, Entrepreneur.com, TechinAsia, Coindesk, and Cointelegraph. I am a frequent speaker and panelist at tech and blockchain conferences around the globe. I serve as a start-up mentor at Axel Springer Accelerator, NY Edtech Accelerator, Seedstars, and Learnlaunch Accelerator. I love hackathons and often serve as a technical judge on hackathon panels.

Recent Posts

Blockchain in Elections: A Leap Toward Transparent Democracy

In 2024 we're witnessing a critical point in democratic technology: the integration of blockchain and…

3 weeks ago

Win Big with Our Amazon Fire Max 11 & AirPods Pro Giveaway!

We’re thrilled to announce an exciting opportunity for you to win not one but two…

2 months ago

Unleashing Potential: How Education Ecosystem Transforms Learning into Real-World Success

Acquiring practical skills is crucial for career advancement and personal growth. Education Ecosystem stands out…

4 months ago

The Role of Artificial Intelligence in Modern Software Development

Artificial Intelligence (AI) has been making significant strides in various industries, and the software development…

7 months ago

Highest Stable Coin Yields – (W16 – 2024)

Another week to bring you the top yield platforms for three of the most prominent…

8 months ago

LEDU Token OTC Trading

If you hold a large volume of LEDU tokens above 1 million units and wish…

9 months ago