Promises
Understanding Promises
A Promise in short:
"Imagine you are a kid. Your mom promises you that she'll get you a new phone next week."
You don't know if you will get that phone until next week. Your mom can either really buy you a brand new phone, or stand you up and withhold the phone if she is not happy.
That is a promise. A promise has 3 states. They are:
- Promise is pending: You don't know if you will get that phone until next week.
- Promise is resolved: Your mom really buy you a brand new phone.
- Promise is rejected: You don't get a new phone because your mom is not happy.
Creating a Promise
/* ES5 */
var isMomHappy = false;
// Promise
var willIGetNewPhone = new Promise(
function (resolve, reject) {
if (isMomHappy) {
var phone = {
brand:'Samsung',
color:'black'
};
resolve(phone); // fulfilled
} else {
var reason = new Error('mom is not happy');
reject(reason); // reject
}
}
);
The code is quite expressive in itself.
We have a boolean
isMomHappy
, to define if mom is happy.We have a promise
willIGetNewPhone
. The promise can be eitherresolved
(if mom get you a new phone) orrejected
(mom is not happy, she doesn't buy you one).There is a standard syntax to define a new
Promise
, refer to MDN documentation.// promise syntax look like this new Promise( /* executor */ function(resolve, reject) { ... } );
- What you need to remember is, when the result is successful, call
resolve(your_success_value)
, if the result fails, callreject(your_fail_value)
in your promise. In our example, if mom is happy, we will get a phone. Therefore, we callresolve
function withphone
variable. If mom is not happy, we will callreject
function with a reasonreject(reason)
Consuming Promises
Now that we have the promise, let's consume it.
/* ES5 */
...
// call our promise
var askMom = function () {
willIGetNewPhone
.then(function (fulfilled) {
// yay, you got a new phone
console.log(fulfilled);
// output: { brand: 'Samsung', color: 'black' }
})
.catch(function (error) {
// oops, mom don't buy it
console.log(error.message);
// output: 'mom is not happy'
});
};
askMom();
We have a function call
askMom
. In this function, we will consume our promisewillIGetNewPhone
.We want to take some action once the promise is resolved or rejected, we use
.then
and.catch
to handle our action.In our example, we have
function(fulfilled) { ... }
in.then
. What is the value offulfilled
? Thefulfilled
value is exactly the value you pass in your promiseresolve(your_success_value)
. Therefore, it will bephone
in our case.We have
function(error){ ... }
in.catch
. What is the value oferror
? As you can guess, theerror
value is exactly the value you pass in your promisereject(your_fail_value)
. Therefore, it will bereason
in our case.
Chaining Promises
Promises are chainable.
Let's say, you, the kid, promise your friend that you will show them the new phone when your mom buy you one.
That is another promise. Let's write it!
// 2nd promise
var showOff = function (phone) {
return new Promise(
function (resolve, reject) {
var message = 'Hey friend, I have a new ' +
phone.color + ' ' + phone.brand + ' phone';
resolve(message);
}
);
};
In this example, you might realize we didn't call the
reject
. It's optional.We can shorten this sample by using
Promise.resolve
instead.
// 2nd promise
var showOff = function (phone) {
var message = 'Hey friend, I have a new ' +
phone.color + ' ' + phone.brand + ' phone';
return Promise.resolve(message);
};
Let's chain the promises. You, the kid can only start the showOff
promise after the willIGetNewPhone
promise.
// call our promise
var askMom = function () {
willIGetNewPhone
.then(showOff) // chain it here
.then(function (fulfilled) {
console.log(fulfilled);
// output: 'Hey friend, I have a new black Samsung phone.'
})
.catch(function (error) {
// oops, mom don't buy it
console.log(error.message);
// output: 'mom is not happy'
});
};
That's how easy to chain the promise.
Promises are Asynchronous
// call our promise
var askMom = function () {
console.log('before asking Mom'); // log before
willIGetNewPhone
.then(showOff)
.then(function (fulfilled) {
console.log(fulfilled);
})
.catch(function (error) {
console.log(error.message);
});
console.log('after asking mom'); // log after
}
What is the sequence of expected output? Probably you expect:
1. before asking Mom
2. Hey friend, I have a new black Samsung phone.
3. after asking mom
However, the actual output sequence is:
1. before asking Mom
2. after asking mom
3. Hey friend, I have a new black Samsung phone.
Why? Because life (or JS) waits for no man.
You, the kid, wouldn't stop playing while waiting for your mom promise (the new phone). Don't you? That's something we call asynchronous, the code will run without blocking or waiting for the result. Anything that need to wait for promise to proceed, you put that in .then
.