Master the javascript interview: what is a promise?

Introduction to promises

A promise is commonly defined as a proxy for a value that will eventually become available.

Promises are one way to deal with asynchronous code, without getting stuck in callback hell.

Promises have been part of the language for years (standardized and introduced in ES2015), and have recently become more integrated, with async and await in ES2017.

Async functions use promises behind the scenes, so understanding how promises work is fundamental to understanding how and work.

How promises work, in brief

Once a promise has been called, it will start in a pending state. This means that the calling function continues executing, while the promise is pending until it resolves, giving the calling function whatever data was being requested.

The created promise will eventually end in a resolved state, or in a rejected state, calling the respective callback functions (passed to and ) upon finishing.

Which JS APIs use promises?

In addition to your own code and libraries code, promises are used by standard modern Web APIs such as:

  • the Battery API
  • the Fetch API
  • Service Workers

It’s unlikely that in modern JavaScript you’ll find yourself not using promises, so let’s start diving right into them.

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

«Чейнинг» (chaining), то есть возможность строить асинхронные цепочки из промисов – пожалуй, основная причина, из-за которой существуют и активно используются промисы.

Например, мы хотим по очереди:

  1. Загрузить данные посетителя с сервера (асинхронно).
  2. Затем отправить запрос о нём на github (асинхронно).
  3. Когда это будет готово, вывести его github-аватар на экран (асинхронно).
  4. …И сделать код расширяемым, чтобы цепочку можно было легко продолжить.

Вот код для этого, использующий функцию , описанную выше:

Самое главное в этом коде – последовательность вызовов:

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

Если очередной вернул промис, то далее по цепочке будет передан не сам этот промис, а его результат.

В коде выше:

  1. Функция в первом возвращает «обычное» значение . Это значит, что возвратит промис в состоянии «выполнен» с в качестве результата. Он станет аргументом в следующем .
  2. Функция во втором возвращает промис (результат нового вызова ). Когда он будет завершён (может пройти какое-то время), то будет вызван следующий с его результатом.
  3. Третий ничего не возвращает.

Схематично его работу можно изобразить так:

Значком «песочные часы» помечены периоды ожидания, которых всего два: в исходном и в подвызове далее по цепочке.

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

То есть, логика довольно проста:

  • В каждом мы получаем текущий результат работы.
  • Можно его обработать синхронно и вернуть результат (например, применить ). Или же, если нужна асинхронная обработка – инициировать её и вернуть промис.

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

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

В данном случае промис должен перейти в состояние «выполнен» после срабатывания .

Строку для этого нужно переписать так:

Теперь, если к цепочке добавить ещё , то он будет вызван после окончания .

Применяем промисы

Теперь у нас есть промис, давайте применим его:

1. Мы вызываем функцию в . В этой функции, мы применим наш промис .

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

3. В нашем примере, у нас в . Какое значение у ?  значение это точное значение в вашем промисе (значение при успехе). Следовательно, это будет .

4. У нас есть  в . Какое значение будет у ? Как вы могли предположить,  значение именно то, которое вы указали в промисе (значение при неудаче). Следовательно, в этом случае это будет .

Давайте запустим этот пример и увидим результат!

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

Да, в промисах есть цепочки.

Давайте представим, что вы ребенок и обещали своему другу, что покажете ему новый телефон, когда вам его купят. Это будет ещё один промис.

В этом примере вы уже наверное поняли, что мы не вызывали . Так как, в принципе, это опционально.

Мы вообще можем сократить этот пример, используя .

А теперь давайте свяжем наши промисы. Вы — ребенок и можете запустить  промис только после промиса .

Вот так легко связывать промисы.

Сложный кейс с промисами, и главное преимущество промисов — колбеки

Попалась мне интереснейшая задача «Платежная система отвечает об успешной оплате не сразу, поэтому придется слать несколько запросов в течение 30 секунд, при этом держать пользователя в режиме прелоадера, при этом если оплата пройдет раньше чем 30 секунд, то из цикла нужно выйти и отключить прелоадер, и если за 30 секунд ответа не получено, то показать ошибку».

Архитектура:

  1. Интервал запросов к серверу 1 секунда.
  2. Необходим один большой (глобальный) промис, чтобы было удобно отключить прелоадер.
  3. До входа в асинхронный код нужно включить прелоадер.
  4. Внутри асинхронного кода должно произойти «нечто ужасное» без потери читабельности.
  5. Отключение прелоадера должно происходить в финальном коде, независимо от того, успешная оплата, или ошибка, и независимо от того, сколько промисов будет использоваться в асинхронном коде.

Для удобства сопоставления алгоритма и архитектуры код совсем чуть-чуть упрощен, и совпадает с оригинальным на 90%.

Результат:

На данном примере видно как используются колбэки — у нас есть полный простор в передаче ошибок в родительский промис, их множественный вызов в разных местах, когда нам необходимо. И также максимальный простор для выбора момента уведомления «родителя» об успешном окончании, тем самым мы решаем 5 пункт из запланированной архитектуры.

Оркестровые промисы

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

Синтаксис ES2015 деструктуризации позволяет сделать так:

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

Это был пример с . Сейчас давай разберем с реальными данными.
Нам нужно 2 , с которых мы получим данные. Берём 2 учетные записи с github.

Так как мы получаем в качестве ответа поток данных, мы должны его преобразовать в читаемый . Ранее мы делали это с одним ответом через . Как это сделать если у нас два ? Мы перебираем с помощью , который вернет новый массив и на каждом вызываем второй промис .

Почему мы должны вызывать ?

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

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

Promise reaction как последствие исполненного обещания

Как вы могли заметить на рисунке 14, последствия разрешения / резолвинга promise объекта подписаны как «+реакция» и «-реакция». Официальный термин для этих слов из ECMAScript спецификации — promise reaction. Предполагается, что в следующих статьях эта тема будет рассмотрена подробно. Пока что ограничимся общим представлением того, что такое promise reaction, чтобы можно было правильно ассоциировать этот термин с философским смыслом этого слова и его техническим исполнением.

Как мы помним, у обещания могут быть последствия, а могут и не быть. Что же такое последствие? Это действие, которое произойдет некоторым временем позже: после того как обещание исполнится. А раз это действие, то последствие может быть выражено обычной JavaScript функцией. Одни функции исполнятся в случае успешного резолвинга промиса (+реакция); другие функции — в случае, когда промис перейдет в состояние rejected (-реакция). Технически эти функции (последствия) передаются аргументами при вызове метода Promise.prototype.then().

Таким образом важной частью promise reaction является асинхронное действие, выполняемое когда-то в будущем. Есть и вторая важная составляющая часть promise reaction — это новосозданный промис, возвращаемый после выполнения команды Promise.prototype.then()

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

По факту promise reaction связывает обещания между собой в каком-то временном интервале

Важно помнить тот момент, что реакции обрабатываются в автоматическом режиме. Вызовы функций — последствий разрешения промиса — осуществляются движком JS, не программистом (рис. 18)

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

рис 18. ( Последствия разрешения обещания записываются callback функциями в методе then(). Callback будет вызван асинхронно автоматически движком JS )

Compatibility with other libraries #

The JavaScript promises API will treat anything with a method as promise-like (or in promise-speak sigh), so if you use a library that returns a Q promise, that’s fine, it’ll play nice with the new JavaScript promises.

Although, as I mentioned, jQuery’s Deferreds are a bit … unhelpful. Thankfully you can cast them to standard promises, which is worth doing as soon as possible:

Here, jQuery’s returns a Deferred. Since it has a method, can turn it into a JavaScript promise. However, sometimes deferreds pass multiple arguments to their callbacks, for example:

Whereas JS promises ignore all but the first:

Thankfully this is usually what you want, or at least gives you access to what you want. Also, be aware that jQuery doesn’t follow the convention of passing Error objects into rejections.

Promise: Последовательные итерации

На данный момент, на примере приложения веб­-паука, мы рассмотрели объекты Promise и приемы их использования для создания простой элегантной реализации последовательного потока выполнения. Но этот код обеспечивает выполнение лишь известного заранее набора асинхронных операций. Поэтому, чтобы восполнить пробелы в исследовании последовательного выполнения, нам нужно разработать фрагмент, реализующий итерации с помощью объектов Promise. И снова прекрасным примером для демонстрации станет функция spiderLinks().

function spiderLinks(currentUrl, body, nesting) {
  let promise = Promise.resolve();
  if(nesting === 0) {
    return promise;
  }
  const links = utilities.getPageLinks(currentUrl, body);
  links.forEach(link => {
    promise = promise.then(() => spider(link, nesting – 1));
  });
  return promise;
}

Для асинхронного обхода всех ссылок на веб-­странице нужно динамически создать цепочку объектов Promise.

  1. Начнем с определения «пустого» объекта Promise, разрешаемого как undefned. Он будет служить началом цепочки.
  2. Затем в цикле присвоим переменной promise новый объект Promise, полученный вызовом метода then() предыдущего объекта Promise в цепочке. Это и есть шаблон асинхронных итераций с использованием объектов Promise.

В конце цикла переменная promise будет содержать объект Promise, который вернул последний вызов then() в цикле, поэтому он будет разрешен после разрешения всех объектов Promise в цепочке.

Creating a promise: the Promise constructor

To create a promise in JavaScript, you use the constructor:

The constructor accepts a function as an argument. This function is called the .

The executor accepts two functions with the names, by convention, and . 

When you call the , the is called automatically. 

Inside the executor, you manually call the function if the executor is completed successfully and invoke the function in case of an error occurs.

If you embed the above JavaScript code in an HTML document and check the console window, you will see that the promise is resolved because the variable is set to .

To see the pending state of the promise, we wrap the code of the executor in the function:

Now, you see that the promise starts with the state with the value is . The promise value will be returned later once the promise is completed.

After about 3 seconds, type the in the console window, you will see that the state of the promise becomes and the promise value is the string that we passed to the function.

So calling the function moves the promise object to the fulfilled state. If you change the value of the variable to and run the script again:

You will see an error message and the state of the promise becomes after 3 seconds:

In other words, calling the method moves the promise object to the state.

The following picture illustrates the states of a promise and the effect of calling the and functions:

Once the promise reaches either fulfilled state or rejected state, it stays in that state and can’t switch.

In other words, a promise cannot go from the fulfilled state to the rejected state and vice versa. It also cannot go back from the fulfilled state or rejected state to the pending state.

If the promise reaches fulfilled state or rejected state, the promise is resolved.

Once a new object is created, it is in the pending state until it is resolved. To schedule a callback when the promise is either resolved or rejected, you call the methods of the object: , , and .

Выполнение промиса

При запуске мы выполняем промис и ожидаем успешного выполнения, используя обратный вызов .
Так как мы создали промис, а затем сразу же выполнили — передав Alex is cool, мы сразу увидем результат в консоле.

Если нужно сделать через некоторое время

Если мы хотим выполнить некоторую обработку в фоновом режиме или сделать AJAX-запрос, а затем, когда данные вернутся, сделать . По сути, всё сводится к тому, что «я не хочу останавливать выполнение JavaScript, я просто хочу начать запрос, а затем, когда он вернется, разберусь с этим результатом».

Давай посмотрим, что произойдет, когда мы установим здесь тайм-аут в 1 секунду.

Через секунду в консоле появится Alex is cool. Точно так же мы можем вызвать :

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

Теперь в консоле браузера через 1 секунду будет только реальная ошибка, которую мы передали. В идеале, для более детальной информации, где произошла ошибка, мы должны передать объект , а не просто строку. Поэтому мы обернем строку в объект , а затем, когда ошибка выведется в консоль, мы увидим, что у нас есть информация о том, где она произошла.

Концепция 1: Как создать промис и применить его

Рассмотрим следующую асинхронную функцию:

function async_fn() {
setTimeout(function(){
console.log("executed");
}, 1000);
}

Чтобы async_fn вернула результат своей работы, можно:

  1. Использовать callback-функцию.
  2. Использовать промис.

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

Синтаксис создания нового промиса:

new Promise((resolve, reject)=>{
if(success){
resolve("success");
} else {
reject("failed");
}
});

Пример:

function timer() {
return new Promise((resolve, reject)=> {
setTimeout(()=>{
resolve("Timeout");
},2000);
});
}

Класс Promise предоставляет три метода:

  1. thenесли промис выполняется успешно, то будет осуществлен обратный вызов метода then.
  2. catchесли промис не выполняется, будет осуществлен обратный вызов метода catch.
  3. finallyметод вызывается, если промис выполнен.

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

timer().then((response)=>{
// функция, возвращаемая в случае успеха
console.log(response);
}).catch((error)=>{
// функция, возвращаемая в случае ошибки
console.log(error);
}).finally(()=>{
// всегда вызывается
console.log("Promise completed");
});

Объект promise: его философия, техническое представление, возможные состояния

Уже не раз было мною замечено, что качественное обучение программированию должно состоять из 2 частей. Это — философское осмысление идеи, а уже затем её техническая реализация. То есть обычная человеческая логика, которой ученик руководствуется при принятии каких-либо решений, сильно облегчает понимание технической реализации этого решения. Поэтому начнем мы с того, что такое обещание в жизни, и как мы к нему относимся? А затем посмотрим: как примеры обещаний будут реализованы в коде. Рассмотрим следующие рисунки (рис. 1, 2, 3).

рис 1. ( `PromiseState` — как результат обещания )рис 2. ( `PromiseResult` — как информация, связанная с результатом выполненного или невыполненного обещания )рис 3. ( `PromiseFulfillReactions`, `PromiseRejectReactions` — как последствия, которые наступают после выполнения или невыполнения обещания )

Мы видим, что само понятие обещания стоит на 3-х китах. 1) Было ли выполнено обещание вообще? 2) Какую дополнительную информацию мы можем извлечь после выполнения или отказа обещания? 3) Какие последствия наступят в случае положительного или отрицательного исхода нашего обещания?

Технически же обещание — это обыкновенная сущность, выраженная через такой тип данных, как объект. У этой сущности есть имя / класс Promise. Объекты, рожденные от этого класса, имеют в цепочке своих прототипов Promise.prototype. И данная сущность должна быть как-то связана со всей той «информацией из жизни», которую мы рассмотрели выше. Спецификация ECMAScript эту информацию закладывает в промис еще на уровне, который ниже по абстракции, чем сам JavaScript. Например, на уровень С++. Соответственно в объекте промиса есть место и под статус, и под результат, и под последствия обещания. Взгляните на то, из чего состоит обещание по  (рис. 4).

рис 4. ( Внутренние поля promise объекта по версии ECMAScript спецификации )

Какими новыми красками заиграла фраза «обещать — не значит жениться» с точки зрения программиста? 1) `PromiseState`. Кто-то не женился. 2) `PromiseResult`. Потому что ему не хватило денег на свадьбу. 3) `PromiseRejectReactions`. Как следствие — у него появилось куча свободного времени, которое он потратил на саморазвитие 4) `PromiseFulfillReactions`. А зачем человеку план B, когда он уже выбрал план A?

Да, есть и пятое поле `PromiseIsHandled`

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

Если нет, то необработанный reject обещания интерпретируется движком JS как ошибка. Для нетерпеливых: если программист не повесил вторым аргументом через Promise.prototype.then() функцию-callback-обработчик reject-а состояния промиса — то возникшее состояние «rejected» promise объекта покажет вам красную ошибку в консоли разработчика.

Обратили внимание, что поля объекта promise заключены в «]»? Этим подчеркивается, что доступ к данной информации у программиста JS напрямую не имеется. Только через специальные средства / команды / API, как, например, команду Promise.prototype.then()

Если же у вас есть непреодолимое желание управлять «этой кухней» напрямую, то добро пожаловать в клуб разработчиков стандартов спецификации EcmaScript.

Небольшое замечание в конце данной подглавы. Если в жизни у нас могут быть обещания выполнены частично, то в EcmaScript — нет. То есть, если человек обещал отдать миллион, а отдал 950 тысяч, то в жизни, может, он и надежный партнер, но для для JavaScript такой должник будет занесен в черный список через `PromiseState` === «rejected». Promise объект меняет свое состояние однозначно и всего лишь один раз. Как это технически реализуется — немного позже.

Transformation / Chaining

Following our example through, what we really want to do is transform
the promise via another operation. In our case, this second operation
is synchronous, but it might just as easily have been an asynchronous
operation. Fortunately, promises have a (fully standardised,
) method for transforming promises
and chaining operations.

Put simply, is to as is to . To put that another
way, use whenever you’re going to do something with the result
(even if that’s just waiting for it to finish) and use
whenever you aren’t planning on doing anything with the result.

Now we can re-write our original example as simply:

Since is just a function, we could re-write this as:

This is very close to the simple synchronous example we started out with.

How to Use the .then() Promise Handler

The method should be called on the promise object to handle a result (resolve) or an error (reject).

It accepts two functions as parameters. Usually, the method should be called from the consumer function where you would like to know the outcome of a promise’s execution.

If you are interested only in successful outcomes, you can just pass one argument to it, like this:

If you are interested only in the error outcome, you can pass for the first argument, like this:

However, you can handle errors in a better way using the method that we will see in a minute.

Let’s look at a couple of examples of handling results and errors using the and handlers. We will make this learning a bit more fun with a few real asynchronous requests. We will use the PokeAPI to get information about Pokémon and resolve/reject them using Promises.

First, let us create a generic function that accepts a PokeAPI URL as argument and returns a Promise. If the API call is successful, a resolved promise is returned. A rejected promise is returned for any kind of errors.

We will be using this function in several examples from now on to get a promise and work on it.

Utility method to get a Promise

Example 1: Get 50 Pokémon’s information:

Example 2: Let’s try an invalid URL

Promise.resolve/reject

Methods and are rarely needed in modern code, because syntax (we’ll cover it a bit later) makes them somewhat obsolete.

We cover them here for completeness and for those who can’t use for some reason.

creates a resolved promise with the result .

Same as:

The method is used for compatibility, when a function is expected to return a promise.

For example, the function below fetches a URL and remembers (caches) its content. For future calls with the same URL it immediately gets the previous content from cache, but uses to make a promise of it, so the returned value is always a promise:

We can write , because the function is guaranteed to return a promise. We can always use after . That’s the purpose of in the line .

creates a rejected promise with .

Same as:

In practice, this method is almost never used.

Bonus round: promises and generators #

This next bit involves a whole bunch of new ES6 features, but it’s not something you need to understand to use promises in your code today. Treat it like a movie trailer for some upcoming blockbuster features.

ES6 also gives us , which allow functions to exit at a particular point, like «return», but later resume from the same point and state, for example:

Notice the star before the function name. This makes it a generator. The keyword is our return/resume point. We can use it like this:

But what does this mean for promises? Well, you can use this return/resume behaviour to write async code that looks like (and is as easy to follow as) synchronous code. Don’t worry too much about understanding it line-for-line, but here’s a helper function that lets us use to wait for promises to settle:

… which I pretty much , but adapted for JavaScript promises. With this, we can take our final best-case chapter example, mix it with a load of new ES6 goodness, and turn it into:

This works exactly as before but is so much easier to read. This works in Chrome and Opera today, and works in Microsoft Edge by going to and turning on the Enable experimental JavaScript features setting. This will be enabled by default in an upcoming version.

This throws together a lot of new ES6 stuff: promises, generators, let, for-of. When we yield a promise, the spawn helper waits for the promise to resolve and returns the final value. If the promise rejects, spawn causes our yield statement to throw an exception, which we can catch with normal JavaScript try/catch. Amazingly simple async coding!

This pattern is so useful, it’s coming to ES7 in the form of async functions. It’s pretty much the same as above, but no need for a method.

Combine promises

If running multiple promises in parallel, you can combine them to wait for the whole with :

var p1 = new Promise(function (resolve, reject, notify) {
    setTimeout(resolve, 2000, 'p1');
});

var p2 = new Promise(function (resolve, reject, notify) {
    setTimeout(resolve, 1000, 'p2');
});

Promise.all(p1, p2).then(function (values) {
    console.log(values);
});

// Will console.log() at least 2000 ms after

Or race them to find the first to solve with :

var p1 = new Promise(function (resolve, reject, notify) {
    setTimeout(resolve, 2000, 'p1');
});

var p2 = new Promise(function (resolve, reject, notify) {
    setTimeout(resolve, 1000, 'p2');
});

Promise.race(p1, p2).then(function (value) {
    console.log(value);
});

// Will console.log('p2') at least 1000 ms after

NB : Note that eventual notifications from combined promises and will be passed in the order they happen to the resulting promise watchers, see the section. Notifications from late promises won’t no more be catched as soon as a resolution state will be determined.

Promise.all

Let’s say we want many promises to execute in parallel and wait until all of them are ready.

For instance, download several URLs in parallel and process the content once they are all done.

That’s what is for.

The syntax is:

takes an array of promises (it technically can be any iterable, but is usually an array) and returns a new promise.

The new promise resolves when all listed promises are settled, and the array of their results becomes its result.

For instance, the below settles after 3 seconds, and then its result is an array :

Please note that the order of the resulting array members is the same as in its source promises. Even though the first promise takes the longest time to resolve, it’s still first in the array of results.

A common trick is to map an array of job data into an array of promises, and then wrap that into .

For instance, if we have an array of URLs, we can fetch them all like this:

A bigger example with fetching user information for an array of GitHub users by their names (we could fetch an array of goods by their ids, the logic is identical):

If any of the promises is rejected, the promise returned by immediately rejects with that error.

For instance:

Here the second promise rejects in two seconds. That leads to an immediate rejection of , so executes: the rejection error becomes the outcome of the entire .

In case of an error, other promises are ignored

If one promise rejects, immediately rejects, completely forgetting about the other ones in the list. Their results are ignored.

For example, if there are multiple calls, like in the example above, and one fails, the others will still continue to execute, but won’t watch them anymore. They will probably settle, but their results will be ignored.

does nothing to cancel them, as there’s no concept of “cancellation” in promises. In another chapter we’ll cover that can help with that, but it’s not a part of the Promise API.

allows non-promise “regular” values in

Normally, accepts an iterable (in most cases an array) of promises. But if any of those objects is not a promise, it’s passed to the resulting array “as is”.

For instance, here the results are :

So we are able to pass ready values to where convenient.

Плюсы и минусы в теории

Async/awaitПлюсы

  • Удобство и простота чтения
  • Возможность использования последовательного стиля программирования

Минусы

  • Легко наткнуться на избыточное ожидание последовательного кода. Для истинной параллельности нужно модифицировать код.
  • Неочевидность возвращаемых значений try…catch.

PromiseПлюсы

  • Использует традиционный подход колбэков.
  • Данные с ошибками и данные с успешным результатом операции однозначно понимаемы.
  • Возможность использовать Promise.all без оглядки на синтаксис.
  • Оповещения Promise.resolve и Promise.reject доступны везде.
  • Наглядное использование метода Promise.finally.

Минусы

При неправильном использовании возможно создание слишком глубоких использований цепочек .then

JavaScript Promise Object

A JavaScript Promise object contains both the producing code and calls to the consuming code:

Promise Syntax

let myPromise = new Promise(function(myResolve, myReject) {
// «Producing Code» (May take some time)
  myResolve(); // when successful
  myReject();  // when error
});
// «Consuming Code» (Must wait for a fulfilled Promise)
myPromise.then(
  function(value) { /* code if successful */ },
  function(error) { /* code if some error */ }
);

When the executing code obtains the result, it should call one of the two callbacks:

Result Call
Success myResolve(result value)
Error myReject(error object)
Добавить комментарий

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

Adblock
detector