Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

new Promise JS: Асинхронное программирование

Если в проекте появились промисы, то, по-хорошему, весь код должен работать только через них. К сожалению, далеко не все библиотеки имеют интерфейс с промисами и работают по старинке, на колбеках. В таких случаях функции нужно "обернуть" или, как говорят, "промисифицировать". Создание промиса происходит с помощью конструктора Promise:

import fs from 'fs';

const promise = new Promise((resolve, reject) => {
  fs.readFile('/etc/passwd', (err, data) => {
    if (err) {
      reject(err);
      return;
    }
    resolve(data);
  });
});

Промис ожидает на вход функцию, которая будет вызвана в момент создания. Именно внутри этой функции и нужно выполнять асинхронную операцию (на колбеках), которую мы хотим превратить в промис. Промис прокидывает в эту функцию два колбека:

  • resolve — должна быть вызвана в случае успешного завершения асинхронной операции. Ей на вход отдаётся результат этой операции.
  • reject — должна быть вызвана в случае ошибки. На вход, соответственно, отдаётся ошибка.

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

В конечном итоге конструкция new Promise() возвращает самый настоящий промис, с которым можно работать уже привычным для нас способом:

promise
  .then(console.log)
  .catch(console.log)

А что, если нужно обернуть две асинхронных операции или три, или даже больше? Придётся оборачивать каждую из них независимо. Другими словами, одна асинхронная операция — один конструктор new Promise. Кстати, эту задачу можно автоматизировать, и в ноду встроена специальная функция, которая делает промисы из асинхронных функций:

import util from 'util';
import fs from 'fs';

const stat = util.promisify(fs.stat);
stat('.').then((stats) => {
  // Do something with `stats`
}).catch((error) => {
  // Handle the error.
});

Во фронтенде такое тоже возможно, достаточно "загуглить" пакет, предоставляющий функцию promisify.

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

const promise = new Promise((resolve) => resolve());
// promise.then ...

То же самое для промиса, который завершается неуспешно:

const promise = new Promise((resolve, reject) => reject());
// promise.catch ...

Для этих задач добавили специальные сокращения, с которыми код становится чище:

const promise1 = Promise.resolve();
// promise1.then

const promise2 = Promise.reject();
// promise2.catch ...

Устройство

Состояния промиса

С технической точки зрения, промис — это объект, имеющий три состояния (см. конечные автоматы и автоматное программирование): pending, fulfilled и rejected. Промис начинается в состоянии pending, а затем, с помощью функций ("событий", как говорят в теории автоматов) resolve и reject переводится в одно из конечных (терминальных) состояний fulfilled или rejected. Перейдя однажды в эти состояния, промис уже не может откатиться назад или уйти в другое терминальное состояние. То есть после вызова resolve, нет способа привести промис в состояние rejected, вызывая функцию reject.


Дополнительные материалы

  1. util.promisify
  2. Автоматное программирование

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.

Об обучении на Хекслете

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
900
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 130 курсов, 2000+ часов теории
  • 900 практических заданий в браузере
  • 360 000 студентов
Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Фронтенд-разработчик
Профессия
Разработка фронтенд-компонентов веб-приложений
18 мая 10 месяцев
Иконка программы Node.js-разработчик
Профессия
Разработка бэкенд-компонентов веб-приложений
18 мая 10 месяцев
Иконка программы Fullstack-разработчик
Профессия
Новый
Разработка фронтенд и бэкенд компонентов веб-приложений
18 мая 16 месяцев

Используйте Хекслет по максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»