Обещания в javascript — важная концепция, которую необходимо понимать разработчику javascript. Если эта концепция ясна, разработчик может использовать ее различными способами в своей повседневной жизни.

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

Что такое обещание?

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

Почему мы используем промисы в JavaScript?

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

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

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

Как на самом деле работают промисы в Javascript?

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

Представьте, вы пообещали своей девушке, что купите ей дорогой подарок. Вы не знаете, сможете ли вы сдержать свое обещание. Может быть, вы сможете сдержать свое обещание, а может быть, и нет.

Итак, если вы обещали, но так и не успели приобрести подарок, обещание находится в состоянии ожидания. Если вы можете сдержать свое обещание, то ваше обещание выполнено. Но если по какой-то причине вы не можете этого сделать, ваше обещание находится в состоянии отклонения.

Когда в Javascript появилось обещание?

Обещания — не новая концепция. На самом деле они существуют с 1976 года, когда этот термин был впервые введен. В начале 2011 года концепция этого стала популярной благодаря отложенным объектам jQuery. Концепция отложенных объектов похожа на промисы, но они не соответствуют точной технической спецификации, как указано в сценарии ECMA 2015 для промисов.

Наконец, обещания были официально добавлены в спецификацию сценария ECMA 2015, а также реализованы во всех последних браузерах и в Node Js.

Разные состояния в обещании

Те же концепции применимы и к обещаниям. Обещание имеет одно из следующих состояний. Вот они:

  1. Ожидание: задача, связанная с обещанием, еще не выполнена или отклонена.
  2. Выполнено: задача, связанная с обещанием, выполнена успешно.
  3. Отклонено: задача, связанная с обещанием, не выполнена.

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

Знакомство с объектом Promise

В приведенном выше коде мы создали обещание, если значение переменной «isPossibleToPurchaseGift» установлено в true, то обещание разрешено. Наконец, мы отображаем разрешенное состояние обещания в окне консоли браузера.

Если мы посмотрим ближе в окне консоли, мы сможем расширить объект Promise, затем, если мы расширим выделенную часть, как показано на снимке экрана ниже, мы сможем получить то же, что показано на снимке экрана ниже.

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

Статические методы в объекте обещания

  • Promise.all(promises): ожидает разрешения всех промисов и возвращает массив всех результатов промисов. Здесь важно отметить, что если какое-либо обещание не выполнено, это становится ошибкой Promise.all, а все остальные результаты игнорируются.
  • Promise.allSettled(promises) : это недавно добавленный метод. Его цель — дождаться выполнения всех промисов и вернуть их результаты в виде массива объектов со состоянием (которое может быть либо «выполнено», либо «отклонено») и значением (если выполнено) или резоном (если отклонено).
  • Promise.race(promises) : он ожидает разрешения первого обещания, и его результат или ошибка становятся результатом.
  • Promise.resolve(value) : создает разрешенное обещание с заданным значением.
  • Promise.reject(error) : генерирует отклоненное обещание с указанной ошибкой.

Создание обещания в Javascript

В приведенном выше коде мы создали обещание с именем «willGetNewGift». Конструктор промисов принимает два параметра: первый — это функция разрешения, а второй — функция отклонения.

Что такое Promise Resolve в Javascript?

Проще говоря, функция разрешения указывает, что если обещание выполнено успешно, то объект обещания разрешается с заданным значением. Итак, в приведенном выше фрагменте кода, если для переменной « willGetNewGift» установлено значение true, обещание вернет объект подарка.

Что такое обещание отклонения в Javascript?

Функция reject возвращает объект обещания, который был отклонен с сообщением об ошибке. В приведенном выше фрагменте кода, если для переменной «willGetNewGift» установлено значение false, то это обещание вернет объект ошибки.

Вызов обещания в Javascript

В приведенном выше коде мы вызываем обещание с именем «willGetNewGift», а затем, чтобы получить значение выполненного обещания, мы используем функцию then(). Мы устанавливаем для переменной «isPossibleToPurchaseGift» значение true. Если значение истинно, мы считаем, что обещание разрешено. Итак, мы можем отобразить объект подарка внутри функции then(). Полный код показан ниже.

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

Нетехническая точка зрения

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

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

Техническая точка зрения

  1. Объект обещания способен выполнять асинхронные задачи в javascript. Каждая асинхронная задача будет возвращать объект обещания, и каждый объект обещания будет иметь функцию then, которая может принимать два параметра: обработчик успеха и обработчик ошибок.
  2. Функция then также вернет промис, так что можно связать несколько промисов в цепочку.
  3. Каждый из обработчиков (успеха или ошибки) также может возвращать значение, которое будет передано следующей функции в качестве параметра в цепочке промисов.
  4. Если обработчик возвращает обещание, то следующий обработчик будет вызван только после завершения этого запроса.

Обоснуем сказанное ранее примером.

Реализация цепочки промисов в Javascript

В приведенном выше фрагменте кода мы определили 3 отдельные функции, первая функция «willGetNewGift» возвращает объект обещания, другие функции также возвращают обещания.

Позвольте мне объяснить, что именно произошло. Сначала вызывается функция «willGetNewGift», которая возвращает обещание, затем этот объект обещания передается следующей функции «willAttendDinner», аналогично она также возвращает объект обещания. Опять же, этот объект передается функции «willGoOnALongDrive».

Наконец, результат функции отображается на консоли. Вот почему вы сможете увидеть сообщение «Вы сдержали свое последнее обещание, отправившись в долгую поездку!».

Что такое Promise.all()?

Проще говоря, promise.all() — это метод, который удобен, когда у нас есть несколько обещаний, и нам нужно дождаться завершения каждого отдельного обещания, прежде чем можно будет выполнить следующее обещание.

Согласно документации MDN: Метод Promise.all() возвращает одно значение Promise, которое разрешается, когда все промисы, переданные как итерируемый объект, разрешены или когда итерируемый объект не содержит промисов. Отклоняется по причине первого отклоняемого обещания.

Итак, из документации ясно видно, что если какой-либо объект промиса в массиве отклоняется, весь метод Promise.all() отклоняется.

Как работает Promise.all()?

Из документов MDN мы знаем, что метод Promise.all() принимает итерируемый объект. Под итерируемым объектом подразумевается, что объект можно легко повторять. Строка и массивы являются примерами таких итерируемых объектов.

Как правило, этот метод возвращает ожидающий объект обещания, который разрешается или отклоняется асинхронно, как только обещание в данном итерируемом объекте разрешается или отклоняется.

После успешного разрешения обещания значения соответствующих обещаний будут в том же порядке, в котором они были переданы в методе promise all. Если какое-либо из обещаний в итерируемом объекте будет отклонено, все обещания будут отклонены. Этот инцидент произойдет, даже если остальные обещания будут успешно разрешены.

Реализация Promise.all() в Javascript

В приведенном выше фрагменте кода мы создали 3 функции, каждая из которых возвращает объект обещания. Затем мы вызывали каждую из них в функции Promise.all(), которая возвращала результат промисов внутри массива. Результат этого показан ниже.

Если какое-либо из обещаний не будет выполнено, результатом будет ошибка. Фрагмент кода показан ниже.

Вывод кода показан ниже.

Что такое Promise.race()?

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

Согласно документации MDN, метод Promise.race() возвращает обещание, которое выполняется или отклоняется, как только одно из обещаний в итерируемом объекте выполняется или отклоняется, со значением или причиной из этого обещания.

Реализация Promise.race() в Javascript

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

Являются ли обещания Javascript синхронными или асинхронными?

Во-первых, вы должны знать, что javascript — это однопоточный язык сценариев. Однопоточный означает, что он должен выполнить один блок кода, прежде чем перейти к выполнению следующего блока кода. Проще говоря, код javascript всегда носит блокирующий характер.

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

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

Обоснуем на примере, что промисы асинхронны.

Возможно, вы ожидали следующего вывода.

Перед подарком

Вы сдержали свое последнее обещание, отправившись в долгую поездку!

После вручения подарка

Но фактический результат показан на снимке экрана ниже.

Реализация промисов Javascript более чистым способом

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

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

Вышеприведенный фрагмент кода является примером оболочки обещания.

Следующий фрагмент кода объясняет, как лучше писать промисы.

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

Написание обещаний Javascript с помощью ES6/ES2015, ES7

ES6 или ES2015 представили синтаксис «let», «const» и «толстая стрелка». Используя это, вы можете лучше писать обещания. Мы можем лучше переписать предыдущий пример с помощью ES6. Фрагмент кода показан ниже.

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

ES7 представил синтаксис async и await. После применения этого к нашему коду ES6 нам будет легче понять. Кроме того, нам не нужно использовать функции then и catch. Для обработки ошибок вам нужно использовать синтаксис try…catch javascript.

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

Вывод

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

Первоначально опубликовано на https://www.devhelperworld.in.