Введение в промисы в JavaScript

Вы уже знаете, что использование коллбэк-модели асинхронности легко приводит к ситуации callback hell. Поэтому в JavaScript была введена новая модель под названием промисы (promise). Давайте изучим эту модель.

Промис представляет собой объект, в который параметром передается функция, внутри которой нужно размещать наш асинхронный код:

javascriptlet promise = new Promise(function() {
  // асинхронный код
});

Как вы видите, я записал объект с промисом в переменную promise. В каком-то другом месте кода я могу применить к этой переменной метод then, передав в него функцию с кодом, который должен быть выполнен по завершении асинхронного кода, написанного при создании данного промиса:

javascriptpromise.then(function() {
  // выполнится при завершении асинхронного кода
});

Звучит запутано, поэтому давайте посмотрим на примере. Пусть у меня есть вот такой асинхронный код:

javascriptsetTimeout(function() {
  let result = [1, 2, 3, 4, 5];
}, 3000);

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

Для начала нужно обернуть наш асинхронный код в промис:

javascriptlet promise = new Promise(function() {
  setTimeout(function() {
    let result = [1, 2, 3, 4, 5];
  }, 3000);
});

Этого, однако, не достаточно. Мы должны в явном виде указать, что наш асинхронный код завершился. В этом нам поможет специальная функция завершения, автоматически попадающая в первый параметр функции, если он указан:

javascriptlet promise = new Promise(function(resolve) { // указываем параметр
  setTimeout(function() {
    let result = [1, 2, 3, 4, 5];
  }, 3000);
});

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

javascriptlet promise = new Promise(function(resolve) {
  setTimeout(function() {
    let result = [1, 2, 3, 4, 5];
    resolve(); // завершаем промис
  }, 3000);
});

При этом, если мы хотим передать вовне какой-то результат асинхронного кода, мы можем передать его параметром нашей функции завершения:

javascriptlet promise = new Promise(function(resolve) {
  setTimeout(function() {
    let result = [1, 2, 3, 4, 5];
    resolve(result); // передаем результат
  }, 3000);
});

Можно, конечно же, избавится от промежуточной переменной:

javascriptlet promise = new Promise(function(resolve) {
  setTimeout(function() {
    resolve([1, 2, 3, 4, 5]);
  }, 3000);
});

Теперь в любом другом месте мы можем вызвать метод then нашего промиса:

javascriptpromise.then(function() {
  // сработает по завершению промиса
});

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

javascriptpromise.then(function(result) {
  console.log(result); // выведет массив с результатом
});
Задание 1

Сделайте промис, внутри которого будет задержка в 5 секунд, после которой промис должен выполнится, своим результатом вернув какой-нибудь текст. Выведите этот текст на экран.