These free mini-courses will give you a strong foundation in web development. Track your progress and access advanced courses on HTML/CSS, Ruby and JavaScript for free inside our student portal.
Scroll down...
Promises take asynchronous programming in JavaScript to a new and much more organized level. This lesson covers what promises are, why they were created and how to use them.
The Promise object is used for asynchronous computations. A Promise represents a value which may be available now, or in the future, or never.
A Promise is a proxy for a value not necessarily known when the promise is created. It allows you to associate handlers with an asynchronous action's eventual success value or failure reason. This lets asynchronous methods return values like synchronous methods: instead of immediately returning the final value, the asynchronous method returns a promise to supply the value at some point in the future.
It's kind of awkward to think of something called a promise as representing a value that we never know if it will ever exist. However, that is not the real beauty of promises.
Promises exist to solve the problem presented by "callback hell" and to provide a standardized interface for responding to asynchronous events.
A promise may have one of 3 states:
It is important to note that the state of a promise is immutable once it has been resolved or rejected. That means it will not change.
Creating a promise is fairly simple. A promise can be instantiated with the new
keyword. The constructor takes a callback that accepts two parameters. The first is resolve
and the second is reject
. Here is an example:
var p = new Promise(function(resolve, reject) {
// Do something asynchronous
});
Once you've created a promise, you can use the resolve
and reject
parameters to pass the return values from your successful or failing asynchronous operations.
resolve
and reject
The resolve
and reject
parameters passed to your function are also functions. When you call them, you pass in the value that you want to be returned when the promise succeeds and fails respectively. Let's take a look at how this works.
The following code creates a promise that checks if the current time in milliseconds is even or odd. If it is even, it resolves the string 'Even'
and if not, it rejects with the string 'Odd'
.
var testEven = new Promise(function(resolve, reject) {
if (Date.now() % 2 === 0) {
resolve('Even');
} else {
reject('Odd');
}
});
then
Once you have a promise you'll want to access its result. We can do that by chaining a call to then
on the promise object. By default then
takes up to two parameters. The first being the callback when the promise is resolved and the second being an optional callback if the promise is rejected.
Here is an example using then
to output the result of the promise we created above:
testEven.then(function(result) {
console.log(result);
}, function(err) {
console.error(err);
});
catch
You can think of catch
as a promise that only is concerned with rejections and errors. It gets its name from the keyword catch
that is used in try {} catch(e) {}
blocks. Notice here that it can actually replace the second parameter that handles the rejection:
testEven
.then(function(result) {
console.log(result);
})
.catch(function(err) {
console.error(err);
});
Another important note is that catch
also catches errors when they are thrown and outputs the error message. So even if the promise resolves and there is an error thrown in the resolve call, the chained catch
will be invoked here and output "Boom!"
.
testEven
.then(function(result) {
console.log(result);
throw "Boom!";
})
.catch(function(err) {
console.error(err); //=> Boom!
});
Promise.all
If you have multiple promises that you want to resolve as a collection Promise.all
takes care of this for you with the same simple then
syntax. All that you have to do is pass the collection of promises to Promise.all
and chain then
as you would with a normal promise. The result passed to your then
callback will be a collection with the results of each promise in its corresponding location.
var nums = [1, 2, 3, 4];
nums = nums.map(function(i) {
return Promise.resolve(i + 1);
});
Promise.all(nums)
.then(function(results) {
console.log(results); //=> [ 2, 3, 4, 5 ]
});
Here are the important snippets of code from this lesson.
// Contruct a promise
var testEven = new Promise(function(resolve, reject) {
if (Date.now() % 2 === 0) {
resolve('Even');
} else {
reject('Odd');
}
});
// Call then on a promise
testEven.then(function(result) {
console.log(result);
}, function(err) {
console.error(err);
});
// Call catch
testEven
.then(function(result) {
console.log(result);
})
.catch(function(err) {
console.error(err);
});
testEven
.then(function(result) {
console.log(result);
throw "Boom!";
})
.catch(function(err) {
console.error(err); //=> Boom!
});
// Using Promise.all
var nums = [1, 2, 3, 4];
nums = nums.map(function(i) {
return Promise.resolve(i + 1);
});
Promise.all(nums)
.then(function(results) {
console.log(results); //=> [ 2, 3, 4, 5 ]
});
The use cases and power of promises know no bounds. Literally, everything that is asynchronous can be wrapped into promises. The more promises are used, the more standardized your code will be. So embrace them, because they are the present and future!