Разъяснено с использованием примеров кода и диаграмм.

Верхний уровень абстракции

Как и большинство вещей в языке JavaScript, обещание - это объект. Веб-документация MDN очень хорошо описывает это.

«Обещание - это прокси для значения, не обязательно известного на момент создания обещания. Он позволяет связать обработчики с конечным значением или причиной сбоя асинхронного действия ». - Веб-документы MDN

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

Когда длительный процесс завершается, он либо вызывает

  • resolve (), который разрешает обещание со значением, или
  • reject (), который отклоняет обещание по причине.

Вы определяете, при каких обстоятельствах они вызываются во время создания обещания. Объект Promise гарантирует, что вызывается только одна из вышеуказанных функций и вызывается только один раз.

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

Объект Promise может находиться в одном из трех состояний:

  • в ожидании: исходное состояние
  • выполнено: операция успешно завершена (решено)
  • отклонено: операция не удалась

Дайвинг глубже

Взгляните на приведенный ниже фрагмент кода. Начните со строки 15, где создается обещание. Код также доступен здесь:
https://gist.github.com/VYV7/63de8140448a1501e0bdac6a42cb8023

Строка 15. Объект Promise создается конструктором обещания - Promise (). Конструктор обещания принимает один аргумент - функцию-исполнитель, определенную вами. Функция-исполнитель, в данном случае promExecutor (),, определена в строке 5.

Строка 5. Эта функция-исполнитель, в свою очередь, принимает два аргумента - функции.

  • 1-я функция вызывается, если все прошло хорошо
  • Вторая функция вызывается, если что-то пошло не так.

Функция исполнителя выполняется сразу же, и здесь вы запускаете асинхронный процесс. Асинхронный процесс может быть HTTP-запросом. Чтобы смоделировать такой процесс, я использовал setTimeout ().

Вкратце, setTimeout () вызывает функцию, переданную в качестве первого аргумента, после задержки, переданной в качестве второго аргумента.

setTimeouot( function, delayms )

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

Promise() -> promiseExecutor() -> setTimeout()

Пока функция задержки работает в фоновом режиме, основной поток программы продолжается. Мы вызываем consol.log () в строках 16 и 17, а затем определяем, что мы хотим сделать после задержки (после завершения длительного процесса).

Строка 23. Мы определяем, что делают resolve () и reject (), используя метод then () только что созданного объекта Promise. Обычно это выглядит так:

Promise.then( onResolved(), onRejected() )

Итак, опять же, метод then () принимает в качестве аргументов две функции.

  • Первый соответствует resolve () и
  • второй соответствует reject ().

И снова, resolved () и reject () вызываются из функции-исполнителя - promExecutor () после задержки (после длительного запущенный процесс завершен).

На диаграмме ниже показан поток Promise - посмотрите. Я считаю, что если вы не можете что-то визуализировать, значит, вы этого не знаете. Как только вы получите эту мысленную картину в своей голове, она останется гораздо дольше.

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

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