Promise
designer. It looks like this. const myPromise = new Promise((resolve, reject) => { if (Math.random() * 100 <= 90) { resolve('Hello, Promises!'); } reject(new Error('In 10% of the cases, I fail. Miserably.')); });
resolve
and reject
, they are, respectively, used to indicate the successful and unsuccessful completion of the performing function.resolve
and reject
parameters are also functions, they are used to return values to the promise object. If the calculation succeeds, or the future value is ready, we send this value using the resolve
function. In such a situation they talk about the successful resolution of promis.reject
function. In this case, they say that promis is rejected. Actually, the reject
function accepts any value, however, it is recommended to pass an Error
object to it, as this helps during debugging during stack tracing.Math.random()
function is used to generate random numbers. In 90% of cases, based on the equal probability of issuing different random numbers, the promise will be resolved. In other cases, it will be rejected.myPromise
. How to get access to the values passed by the functions resolve
and reject
? The .then()
function, which is available to all promises, will help us with this. Take a look at how to work with her. const myPromise = new Promise((resolve, reject) => { if (Math.random() * 100 < 90) { console.log('resolving the promise ...'); resolve('Hello, Promises!'); } reject(new Error('In 10% of the cases, I fail. Miserably.')); }); // const onResolved = (resolvedValue) => console.log(resolvedValue); const onRejected = (error) => console.log(error); myPromise.then(onResolved, onRejected); // , myPromise.then((resolvedValue) => { console.log(resolvedValue); }, (error) => { console.log(error); }); // ( 90% ) // resolving the promise ... // Hello, Promises! // Hello, Promises!
.then()
method accepts two callback functions. The first is called when promise is enabled. The second is performed if the promis is rejected.onResolved
and onRejected
. In the role of callback functions, they are passed to the .then()
method. You can write the same shorter, it is shown in the same example below. The capabilities of such a design do not differ from those of the one where the functions were described before transferring them .then()
.myPromise
. Then we doubled the .then()
handler to it. Both the one and the other have the same functionality, but they are perceived as different entities. In this regard, the following should be noted:then()
) was added to it after this event, then the correct callback function would be called, although the promise was allowed or rejected before the connection .then()
..then()
handlers to the promise.console.log()
call at the very beginning of the example. When the code is run and two .then()
handlers are attached to it, the console.log()
call will be executed only once. This indicates that promis caches the result and, when another .then()
connected, does the same..start()
or .begin()
that could be used to force the promise to run. In the previous example, this is exactly what happens..then()
is called, that is, the onRejected
function. Consider an example. const myPromise = new Promise((resolve, reject) => { if (Math.random() * 100 < 90) { reject(new Error('The promise was rejected by using reject function.')); } throw new Error('The promise was rejected by throwing an error'); }); myPromise.then( () => console.log('resolved'), (error) => console.log(error.message) ); // ( 90% ) // The promise was rejected by using reject function.
onResolved
and onRejected
callback functions are declared. Please note that the onRejected onRejected
will be executed even if an error is thrown during the execution of the promise code. There is no need to explicitly reject the promise by passing the object of the error to the reject
function. That is, the promise will be rejected in both cases..then(null, () => {...})
, if we need to handle errors, we can use the .catch(onRejected)
construct, which accepts one callback - onRejected
. This is how the new fragment of the above code will look when adding this mechanism to it. myPromise.catch( (error) => console.log(error.message) );
.catch()
, in fact, just “ syntactic sugar ” for .then(undefined, onRejected)
..then()
and .catch()
always return promises. Therefore, you can combine multiple .then()
calls into chains. Let's sort it out by example.delay()
function that returns a promise. Returned promis will be resolved after a specified time. This is what this function looks like. const delay = (ms) => new Promise( (resolve) => setTimeout(resolve, ms) );
delay()
function takes, as a parameter, the time expressed in milliseconds. The executing function has access to the ms
parameter due to the closure . Here, in addition, there is a call to setTimeout()
, which calls the resolved
function after the specified number of milliseconds has passed, which leads to resolution of promise. Here is how to use this feature. delay(5000).then(() => console.log('Resolved after 5 seconds'));
.then()
calls into a chain. const delay = (ms) => new Promise( (resolve) => setTimeout(resolve, ms) ); delay(2000) .then(() => { console.log('Resolved after 2 seconds') return delay(1500); }) .then(() => { console.log('Resolved after 1.5 seconds'); return delay(3000); }).then(() => { console.log('Resolved after 3 seconds'); throw new Error(); }).catch(() => { console.log('Caught an error.'); }).then(() => { console.log('Done.'); }); // Resolved after 2 seconds // Resolved after 1.5 seconds // Resolved after 3 seconds // Caught an error. // Done.
delay
function is called. Then the following happens here:delay(2000)
function returns a promise that resolves after 2 seconds..then()
block is executed. He writes Resolved after 2 seconds
to the log. It then returns another promise, causing delay(1500)
. If .then()
returns a promise, the resolution (technically called settlement) of this promise is passed to the next .then()
call.throw new Error()
command, that is, we throw an error into .then()
. This means that the current promise will be rejected, and the next .catch()
handler will be called. As a result, the line Caught an error
is displayed in the log. That is why the .then()
block that .catch()
after .catch()
called.catch()
, not .then()
with onResolved
and onRejected
. Here is the code that clarifies this recommendation. const promiseThatResolves = () => new Promise((resolve, reject) => { resolve(); }); // UnhandledPromiseRejection promiseThatResolves().then( () => { throw new Error }, (err) => console.log(err), ); // promiseThatResolves() .then(() => { throw new Error(); }) .catch(err => console.log(err));
.then()
with two callbacks, onResolved
and onRejected
, you can handle errors and situations in which the promise is rejected, only for the performing function. Suppose the handler in .then()
also throws an error. This, as can be seen from the code, will not result in a call to the onRejected onRejected
..catch(
) block after .then()
, this block will intercept both .catch(
function errors and .then()
errors. This makes sense, since .then()
always returns a promise.fs
and in other modules are based on callbacks. There are utilities that allow you to automatically convert such functions into constructions based on promises. Let's say it's util.promisify from Node.js, and pify .Promise.all
, Promise.race
, and others. In addition, error handling is very briefly covered here. There are well-known anti-patterns and subtleties that you should know about when working with promises. Here are some materials that would be useful for those who are interested in all this: ECMA specification , Mozilla Docs materials , Google promises guide, Exploring JS chapter on promises, useful article on promises basics.Source: https://habr.com/ru/post/358808/
All Articles