By Ran Bar-Zik | 1/9/2018 | General |Beginners

JavaScript Promises in ECMAScript 6

JavaScript Promises in ECMAScript 6

In my opinion, promises are the most important feature is ES6. In today’s world of JavaScript, we have a huge amount of communication with other servers, regardless of whether we’re writing a client-side or server-side script. If we’re talking about server-side, Node.js is quite strong when it comes to I/O (input/output) and for when we have a lot of calls to the database, other servers, or a file system. The calls depend upon one another and what generally happens is that a callback calls to a callback, which creates for us a sort of ‘callback hell.’ On the client-side as well there are often calls that depend on one another. To the back-end again and again, then to the statistic server, and again into callback hell. What exactly is this callback hell you ask? Something like this:

       }

     })

   })

 }

})

Anyone who’s written any modern JavaScript knows what we’re talking about. There are few solutions to this problem, but the most elegant one is promises. There are other reasons to use promise, but this is the main one.

 

In general, promise is just what it sounds like, a promise. We ask a particular function of object something, and get a promise from it. Then, we can set what will happen if that promise is kept or not—if it fails or succeeds.

myPromise.then(function(data) {
//success
 }, function(error) {
//fail
 })

Here we see an object called myPromise of the type promise. This represents ‘my promise.’ In a minute I’ll talk about how to create it. But this promise object is unique and it can succeed or fail. I simply set what it will do if the promise succeeds (that’s the first callback that’s passed by then) or fails (the second callback).

 

I can also concatenate promises. In that case, each then will return a promise object. For example this:

myPromise.then(function(paramater) {
   console.log('Got data! Promise fulfilled.');
   return data;
 }, function(parameter2) {
   console.log('Promise rejected.')
.then(function(data){
  //do another thing, it will be called after the first promise was fulfilled.
}).
.then(function(data){
  //do third thing, it will be called after the last promise was fulfilled.
});

This saves me from callback hell. So how do we create this special promise object? Via the promise object. Have a look:

var myPromise = new Promise(function(resolve, reject) {
       resolve(paramater); // Promise resolved!
       reject(parameter2); // Promise rejected!
   };
 });

I know this isn’t the most tangible example, so let’s make it a bit more clear:

var myPromise = new Promise(function(resolve, reject) {
       resolve('promise resolved');
});

myPromise.then(function(data) {
   return data + ' 1 ';
})
.then(function(data){
  return data + ' 2 ';
})
.then(function(data){
  console.log(data); //promise resolved 1  2
});

If you run this, you’ll see that in the console you get “promise resolved 1 2”. Let examine why.

 

In the first block, I create an object of the type promise and put in into myPromise. The code inside of the callback runs immediately. In this case I implement resolve immediately, meaning I fill the promise right away with the text “promise resolved.”

 

But who cares that the promise was fulfilled? What does it do? It adds a 1 to the information received (in this case the text “promise received”) and returns it. And to whom does it return it? To then which is concatenated right after it and takes the information, adds 2, and concatenates it to the third then which prints the whole thing.

 

Confusing? Let’s take a look at another example that’s a bit more realistic and simpler, without all the concatenations. Let’s say we want to print a joke from an API. We’ll use this API that dishes out random jokes (yes, it’s real): https://api.icndb.com/jokes/random. Follow the link and you’ll get a random joke. Let’s try to display it.

 

This is how we can execute the code using promise:

var myPromise = new Promise(function(resolve, reject) {
 var request = new XMLHttpRequest();

 request.open('GET', 'https://api.icndb.com/jokes/random');
 request.onload = function() {
   if (request.status == 200) {
     resolve(request.response); // we got data here, so resolve the Promise
   } else {
     reject(Error(request.statusText)); // status is not 200 OK, so reject
   }
 };

 request.onerror = function() {
   reject(Error('Error fetching data.')); // error occurred, reject the  Promise
 };

 request.send(); //send the request
});

myPromise.then(function(data) {
 console.log('Got data! Promise fulfilled.');
 document.getElementsByTagName('body')[0].textContent = JSON.parse(data).value.joke;
}, function(error) {
 console.log('Promise rejected.');
 console.log(error.message);
})

 

What’s going on here? First I’m building my promise. Inside of it I make an AJAX call that can either succeed or fail. If it succeeds it fulfills the promise and passes the data. If it fails, so does the promise.

 

In myPromise I receive the promise. This code won’t run so long as the AJAX call hasn’t succeed or failed yet. As soon as the call succeeds, we print the joke. If it fails, we’ll write a message to the log.

 

If you’re still not clear, play around with the code a bit. It’s an important concept to understand.

Promise All

If we have several promises, we can concatenate them and run a function that will run if all the promises succeed. For example:

var myPromise1 = new Promise(function(resolve, reject) {
 var request = new XMLHttpRequest();
 
 request.open('GET', 'http://api.icndb.com/jokes/random');
 request.onload = function() {
   if (request.status == 200) {
     resolve(request.response); // we got data here, so resolve the Promise
   } else {
     reject(Error(request.statusText)); // status is not 200 OK, so reject
   }
 };
 
 request.onerror = function() {
   reject(Error('Error fetching data.')); // error occurred, reject the  Promise
 };
 
 request.send(); //send the request
});
 
var myPromise2 = new Promise(function(resolve, reject) {
 var request = new XMLHttpRequest();
 
 request.open('GET', 'http://numbersapi.com/42/trivia');
 request.onload = function() {
   if (request.status == 200) {
     resolve(request.response); // we got data here, so resolve the Promise
   } else {
     reject(Error(request.statusText)); // status is not 200 OK, so reject
   }
 };
 
 request.onerror = function() {
   reject(Error('Error fetching data.')); // error occurred, reject the  Promise
 };
 
 request.send(); //send the request
});
 
Promise.all([myPromise1, myPromise2])
 .then(function(data) {
 document.getElementsByTagName('body')[0].textContent=JSON.parse(data[0]).value.joke;
 document.getElementsByTagName('body')[0].textContent+=data[1];
 console.log(data)
}, function (err) {
 console.log(`error: ${err}`)
})

Don’t be alarmed, we have here promise1 and promise2. They’re both regular promises which we’ve already seen how to create. One points to an API and the second to a site. In order to run code that runs only after both promises are fulfilled, we’ll use the Promise.all method that takes an array of all the promises that are supposed to be fulfilled. If this happens, we receive an array (data in this case) that’s made up of the information that all the promises pass to us, with which we’re free to do as we please.

 

We also have the race method that works on the same principles as all, but it runs as soon as one call succeeds and then ignores the rest. I’ve never used it and I’m having trouble envisioning a scenario in which one would actually have use for it, but it’s there if you have one.

 

To sum up, promise is one of the most important and useful features of ES6 and it’s important to be acquainted with it.

 

Previous article: Separate scope of each block with let

Next Article: Keepin' it Classy in ECMAScript

 

About the author: Ran Bar-Zik is an experienced web developer whose personal blog, Internet Israel, features articles and guides on Node.js, MongoDB, Git, SASS, jQuery, HTML 5, MySQL, and more. Translation of the original article by Aaron Raizen.

 

By Ran Bar-Zik | 1/9/2018 | General

{{CommentsModel.TotalCount}} Comments

Your Comment

{{CommentsModel.Message}}

Recent Stories

Top DiscoverSDK Experts

User photo
3355
Ashton Torrence
Web and Windows developer
GUI | Web and 11 more
View Profile
User photo
3220
Mendy Bennett
Experienced with Ad network & Ad servers.
Mobile | Ad Networks and 1 more
View Profile
User photo
3060
Karen Fitzgerald
7 years in Cross-Platform development.
Mobile | Cross Platform Frameworks
View Profile
Show All
X

Compare Products

Select up to three two products to compare by clicking on the compare icon () of each product.

{{compareToolModel.Error}}

Now comparing:

{{product.ProductName | createSubstring:25}} X
Compare Now