left-icon

ECMAScript 6 Succinctly®
by Matthew Duffield

Previous
Chapter

of
A
A
A

CHAPTER 14

Promises

Promises


Promises provide a standard implementation of handling asynchronous programming in JavaScript without using callbacks. One of the biggest side effects of using the callback pattern is how dreadfully ugly your code can get with only a few levels of callbacks.

Promises allow you to develop asynchronous scripts more easily than using callbacks. A promise represents a value that we can handle at some point in the future. Promises give us two main advantages over callbacks:

  • No other registered handlers of that value can change it. A promise contract is immutable.
  • We are guaranteed to receive the value, regardless of when we register a handler for it, even if it’s already resolved. This contrasts with events since once an event is fired you can’t access its value at a later time.

Let’s look at the following example:

Code Listing: 195

var p2 = Promise.resolve("foo");

p2.then((res) => console.log(res));

var p = new Promise(function(resolve, reject) { 

  setTimeout(() => resolve(4), 2000);

});

p.then((res) =>

  res += 2

  console.log(res);

});

p.then((res) => console.log(res));

In the first line, we create a promise and resolve it immediately. This demonstrates the second advantage. We can still call on the promise and get the value from it, unlike events. Next, we define a standard promise and have it resolve after two seconds. Our handler receives the value from the promise but cannot change the value of the promise itself. This is good in that our promise is immutable and always returns the same result when called multiple times.

The following is the output from the preceding example:

Code Listing: 196

foo

6

4

Up until now, we have only resolved promises. What about when we reject a promise? Consider the following code:

Code Listing: 197

var p = new Promise(function(resolve, reject) { 

  setTimeout(() => reject("Timed out!"), 2000);

});

p.then((res) => console.log(res),

     (err) => console.log(err));

This time, we are calling reject after our two second delay. We see that then()can also take in a second handler for errors.

The following is the output from the preceding example:

Code Listing: 198

Timed out!

But wait, you can write this even more differently! Consider the following code:

Code Listing: 199

var p = new Promise(function(resolve, reject) { 

  setTimeout(() => reject("Timed out!"), 2000);

});

p.then((res) => console.log("Response:", res))

  .catch((err) => console.log("Error:", err));

You can use the catch function off of the promise as well. Our output will be exactly the same:

Code Listing: 200

Error: Timed out!

Let’s consider another example, when an exception happens. Consider the following code:

Code Listing: 201

var p = new Promise(function(resolve, reject) { 

  setTimeout(() => {throw new Error("Error encountered!");}, 2000);

});

p.then((res) => console.log("Response:", res))

  .catch((err) => console.log("Error:", err));

     

Throwing an Error is the same as calling reject(). You are able to catch the error and handle it accordingly.

The following is the output from the preceding example:

Code Listing: 202

Error encountered!

Promise.all

One nice thing about promises is that many synchronous tools still work, because promise-based functions return results.

Consider the following example:

Code Listing: 203

var fileUrls = [

  'http://example.com/file1.txt',

  'http://example.com/file2.txt'

];

var httpGet = function(item) {

  return new Promise(function(resolve, reject) { 

    setTimeout(() => resolve(item), 2000);

  });

};

var promisedTexts = fileUrls.map(httpGet);

Promise.all(promisedTexts)

  .then(function (texts) {

    texts.forEach(function (text) {

      console.log(text);

    });

  })

  .catch(function (reason) {

    // Receives first rejection among the promises

  });

     

In this example, we are using an asynchronous call to load files. The elegance of this code is that then() will not be called until all of the promises have completed. However, if any of the promises fail, the catch() handler will be called.

Promise.race

Sometimes we don’t want to wait until all of the promises have completed; rather, we want to get the results of the first promise in the array to fulfill. We can do this with Promise.race() which, like Promise.all(), takes an array of promises. However, unlike Promise.all(), it will fulfill its returned promise as soon as the first promise in that array fulfills.

Code Listing: 204

function delay(ms) { 

  return new Promise((resolve, reject) => {

    setTimeout(resolve, ms);

  });

}

Promise.race([ 

  delay(3000).then(() => "I finished second."),

  delay(2000).then(() => "I finished first.")

])

.then(function(txt) {

   console.log(txt); 

})

.catch(function(err) {

  console.log("error:", err);

});

     

Here, we are using a helper function, delay(), that will timeout after a certain amount of time. We create our promise passing in an array. Next, we simply dump out what happens.

The following is the output from the preceding example:

Code Listing: 205

I finished first.

As you can see, the first promise that fulfills is what we get in our then() handler.

Scroll To Top
Disclaimer
DISCLAIMER: Web reader is currently in beta. Please report any issues through our support system. PDF and Kindle format files are also available for download.

Previous

Next



You are one step away from downloading ebooks from the Succinctly® series premier collection!
A confirmation has been sent to your email address. Please check and confirm your email subscription to complete the download.