📜 ⬆️ ⬇️

Promises 101

Translation of the first part of an excellent article about promises. Basic techniques for creating and managing promises.


Promises are used for operations whose calculation takes indefinite time. An example of such an operation could be a network request when we request data from the API and cannot determine exactly when a response will be received.



If there are other operations that depend on this network request, then a problem will appear. Without promises, we have to use a string of callbacks to build a sequence of operations. This is normal if we have one asynchronous action. But if you need to take several consecutive asynchronous steps, callbacks become unmanageable and the result is notorious as callback hell


doSomething(function(responseOne) { doSomethingElse(responseOne, function(responseTwo, err) { if (err) { handleError(err); } doMoreStuff(responseTwo, function(responseThree, err) { if (err) { handleAnotherError(err); } doFinalThing(responseThree, function(err) { if (err) { handleAnotherError(err); } //  }); //  doFinalThing }); //  doMoreStuff }); //  doSomethingElse }); //  doSomething 

Promises provide a standardized and understandable method for solving problems that must be performed consistently.


 doSomething() .then(doSomethingElse) .catch(handleError) .then(doMoreStuff) .then(doFinalThing) .catch(handleAnotherError) 

Creating promises


Promises are created using the constructor of promises. It is a function with two arguments ( resolve & reject ) as parameters.


 var promise = new Promise(function(resolve, reject) { /*   */ } ) 

Designer Promisov
Inside this function, we can perform any asynchronous tasks. To mark promises as executed , we call resolve() , passing it the value we want to return. To mark a promise as rejected or unsuccessful, we call reject() , passing an error message to it. Before the promise is executed or rejected, it is in a state of waiting .


Here is the promis version of XMLHttpRequest -


 /* CREDIT - Jake Archibald, http://www.html5rocks.com/en/tutorials/es6/promises/ */ function get(url) { return new Promise(function(resolve, reject) { var req = new XMLHttpRequest(); req.open('GET', url); req.onload = function() { if (req.status == 200) { resolve(req.response); /*   */ } else { reject(Error(req.statusText)); /*   */ } }; req.onerror = function() { reject(Error("Network Error")); }; req.send(); }); } 

Use of promises


To do a promise, we can call it like any normal function. But, since this is a promise, we have access to a .then method that we can add to the function and that will be executed when the promise goes out of standby mode.


.then() method takes two optional parameters. The first is the function that is called when the promise is executed. The second is a function that is performed if the promise is rejected.


 get(url) .then(function(response) { /* successFunction */ }, function(err) { /* errorFunction */ }) 

.then


Error processing


Since both parameters (successFunction and errorFunction) are optional, we can divide them into two .then() for better readability.


 get(url) .then(function(response) { /* successFunction */ }, undefined) .then(undefined, function(err) { /* errorFunction */ }) 

To make the code even more understandable, we can use the .catch() method, which is a shortcut for .then(undefined, errorFunction)


 get(url) .then(function(response) { /* successFunction */ }) .catch(function(err) { /* errorFunction */ }) 

.catch


Chain formation


The real value of promises is that we can perform several asynchronous functions in order. We can combine .then() and .catch() together to create a sequence of asynchronous functions.


We can do this by returning another promise after completing or rejecting the previous one. For example -


 get(url) .then(function(response) { response = JSON.parse(response); var secondURL = response.data.url return get( secondURL ); /*    */ }) .then(function(response) { response = JSON.parse(response); var thirdURL = response.data.url return get( thirdURL ); /*    */ }) .catch(function(err) { handleError(err); }); 

If the resolved is executed, the nearest .then() in the sequence will be called. If the promise is rejected, then the nearest .catch() in sequence.
chaining


Parallel execution of promises


A situation may arise when we need to perform several promises in parallel, and continue the algorithm only after all promises are completed. For example, if we want to get a series of images and only after that display them on the page.


To do this, we need to use two methods. This is Array.map() , in order to apply a promise for each element of the array and save the result to a new array. And Promise.all() , which will resolve() if all promises are executed in an array. If at least one promise in the array is rejected, Promise.all() will also be rejected.


 var arrayOfURLs = ['one.json', 'two.json', 'three.json', 'four.json']; var arrayOfPromises = arrayOfURLs.map(get); Promise.all(arrayOfPromises) .then(function(arrayOfResults) { /*  -,       */ }) .catch(function(err) { /* ,        */ }) 

Promise.all
If we look into the Network panel of the Development tools, we will see that all requests happen in parallel.


Development tools


If you need support for IE and / or Opera Mini, use a polyfill .
Thanks for attention!


')

Source: https://habr.com/ru/post/312670/


All Articles