Hi everyone, and welcome to another exciting edition of Boring JavaScript. Today, we tackle the concept of Promises.
Don’t want to read? Then check out the video, featuring animation by Shadow Wolf Studios.
I Never Promised You a Rose Garden
But what exactly is a ‘Promise’?
Let’s say a friend comes up to you and asks for a favor. “Certainly” you say. “I promise I’ll get that done for you.”. Your friend then goes about doing what they want to do, and you go off an do the favor. Once you are done, you go back to your friend and report the favor is finished, and that you have kept your promise.
That’s all a Promise is in JavaScript: It is a value returned that ‘promises’ to be completed sometime in the future. In doing so, the routine needing the promise can continue doing other things while the routine performing the Promise works on the task needed. Eventually, the routine working on the promise completes it’s work, reports that back to the routine who requested the promise, and the requester now has data from the Promise.
In short: A Promise is a value in which the state of the promise can change sometime in the future – that is, when the Promise has been made or broken.
Pinky Promise
Creating a promise is done by using ‘new’:
const myPromise = new Promise( (resolve, reject) => {
// code that works on the promise
});
console.log(myPromise); // outputs "Promise {<pending>}"
So what does the ‘pending’ part mean? That’s the initial value of any Promise.
In real life, when you make a promise, the task you promise to do is normally not done immediately – it’s done sometime in the future. For the person to whom you made the promise, there is no resolution to the promise. They only know that you made the promise, but not that it’s been completed. For them, the promise is pending.
And it works the same way with JavaScript. Promises are asynchronous, and as such the initial state of the Promise is pending. Meaning – the object holding the promise (in our case, the variable myPromise) is waiting for the function doing the promise – the callback function passed as the sole argument to the Promise – to complete the function. Thus, the promise is pending. The state will only change once the callback function completes.
And how do we know the promise has completed? When it has been resolved or rejected.
Promises Kept
Take a look at our Promise example again:
const myPromise = new Promise( (resolve, reject) => {
// code that works on the promise
});
console.log(myPromise); // outputs "Promise {<pending>}"
The Promise constructor takes one argument – a callback function. Within that callback function, JavaScript will pass two arguments. These two arguments are what tells the object passed back to the calling function when the Promise is completed. They are functions that your callback function will call to resolve or reject the promise. The first argument is the ‘resolve’ function, and the second argument is the ‘reject’ function.
Resolve is used to inform the routine holding the Promise object that the promise has been fulfilled successfully. Optional data can then be passed to the Promise object. Let’s modify our example.
const myPromise = new Promise( (resolve, reject) => {
if (somethingGoodHappened) {
resolve("all is well");
}
});
console.log(myPromise); // outputs "Promise {<pending>}"
If you run the above, you’ll see that the Promise is still Pending. What gives? Well, it’s the asynchronous nature of a Promise. Code after the creation of the Promise is executed next – before the Promise is resolved. Therefore, it will always show ‘Pending’ in the example above.
How can we fix this? Just hang on..
Promises Broken
A Promise is resolved – meaning everything went great. But what if something happened? That is the reason for the second argument to the callback function – called the Reject argument. Let’s take a look at our example again:
const myPromise = new Promise( (resolve, reject) => {
if (somethingGoodHappened) {
resolve("all is well");
} else {
reject("whoops"};
});
console.log(myPromise); // outputs "Promise {<pending>}"
If something “went wrong” with the Promise, then the promise is rejected. That is where the second argument in the callback function is used.
The Reject argument is used to inform whoever is calling the Promise that the promise had failed in some way, and that it needs to be ‘rejected’. The calling code can then act accordingly to inform someone that something went wrong.
Now We Fix It!
We understand the difference between a ‘Pending’ promise, and ‘Resolved’ promise, and a ‘Rejected’ promise, let’s put things together into code!
// this example is taken from the video. Be sure to watch it!
const results = { skrebert: false, boondit: false, plunkle: false, woodenCase: false };
buildSkrebert(results)
.then(buildBoondit)
.then(buildPlunkle)
.then(allDone)
.catch(mistake);
buildCase(results);
When a Promise is ‘Pending’, it will tell JavaScript to continue processing the very next statement. In our case above, ‘buildSkrebert()’ is executed, followed by ‘buildCase()’. Why? The methods of ‘.then()’ and ‘.catch()’ are used to control execution once a Promise has been ‘Resolved’ or ‘Rejected’. Since our Promise initially is ‘Pending’, then ‘buildCase()’ will be the next statement executed.
However, at some point in the future, the promise returned from ‘buildSkrebert()’ will turn from ‘Pending’ to either ‘Resolved’ or ‘Rejected’. And one of two things will happen:
- If ‘Resolved’, the ‘.then()’ method is executed
- If ‘Rejected’, the ‘catch()’ method is executed
And that’s all there is to it! If ‘buildSkrebert()’ was ‘Resolved’, then it will execute ‘buildBoondit()’, as that is the ‘.then()’ method for ‘buildSkrebert()’. If ‘buildBoondit()’ was ‘Resolved’, then it will execute ‘buildPlunkle()’. If ‘buildPlunkle()’ was ‘Resolved’, then it will execute ‘allDone()’. Finally, if ‘allDone()’ was ‘Resolved’ – well – that’s the end, as there is no more ‘.then()’ methods to execute.
What if something went wrong with ‘buildSkrebert()’ or ‘buildBoondit()’ or ‘buildPlunkle()’ or ‘allDone()’ – meaning, that any one of them went to ‘Rejected’? That is when the ‘.catch()’ method comes in.
For example, suppose ‘buildSkrebert()’ went from ‘Pending’ to ‘Rejected’. Then each of the ‘.then()’ methods will be ignored (as they are executed only for ‘Resolved’ promises), and the ‘.catch()’ methods are executed. In this case, we have only one ‘.catch()’ method, which calls the ‘mistake()’ function.
Can you have more than one ‘.catch()’. Certainly! Just like the ‘.then()’ methods, they will get executed one after another – as long as the returned promise continues to have a state of ‘Rejected’.
And Finally
Besides ‘.then()’ and ‘.catch()’, you can also use the ‘.finally()’ method. It will execute after each ‘.then()’ or each ‘.catch()’ – meaning it will always execute. It’s great for code that needs to be executed for both ‘Resolved’ and ‘Rejected’ promises – like to do data cleanup. It saves you from duplicating code. For example:
buildSkrebert(results)
.then(buildBoondit)
.then(buildPlunkle)
.then(allDone)
.catch(mistake)
.finally(thankFriends);
buildCase(results);
In our example above, no matter if any of the promises are ‘Resolved’ or ‘Rejected’, the ‘thankFriends()’ function will be executed.
The Video
We have a wonderful video, featuring animation done by Shadow Wolf Studios. Check it out!
Shameless Plug
You can find us all over the world!
Special thanks to Shadow Wolf Studios for the wonderful animation to our story. See them at:
Shadow Wolf Studios
Website: http://shadowwolfstudios.net/
YouTube: https://www.youtube.com/channel/UCBhcsEBOwQEckBYYZfvjbSg
Instagram: https://www.instagram.com/shadow_wolf_studio_s/
Pinterest: https://www.pinterest.com/shadowwolfstudios/_saved/
Blog: https://shadowwolfstudios.wordpress.com/
Boring JavaScript
Check out all our videos at: https://www.boringjavascript.com
Check out everything at: https://www.thevirtuoid.com
Facebook: https://www.facebook.com/TheVirtuoid
Twitter: https://twitter.com/TheVirtuoid
YouTube: https://www.youtube.com/channel/UCKZ7CV6fI7xlh7zIE9TWqgw
The Story In The Video
For those who requested it, here is the story from the video:
The Three Friends
One upon a time, there was a person, our Hero, who wanted a genuine hand-made Plunkle. The problem is, our Hero didn’t know how to make one. Besides, you can’t make a Plunkle without a Boondit, and you can’t make a Boondit without a Skrebert. What ever was he to do?
Luckily, our Hero had three friends, one who could make a Skrebert, one who could make a Boondit, and another who could make a Plunkle.
Our Hero went up to the first friend and said, “Can you make me a Skrebert?” “Absolutely!” said the first friend. “I’ll be back in an hour.” So off the first friend went, and our Hero walked over to the second friend. “Can you make me a Boondit” asked our Hero. “Why, of course!” said the second friend. “But I’ll need a Skrebert first”. “I’ll get that to you” said our Hero, “once my friend has made one”. Off walked the second friend, and our Hero approached the third friend. “Can you make me a Plunkle?” “I would be honored” said the third friend, “but first I need a Boondit”. “I will get you that” answered our Hero, “once my friend has made one.” The third friend then walked away and our Hero got to work on making a wooden case for the Plunkle.
About an hour later the first friend appeared. “I have finished your Skrebert!” said the first friend. “Thank you!” said our Hero, who then ran to find the second friend. “I have a Skrebert for you!” said our Hero. “Much abliged” said the second friend, taking the Skrebert. “I’ll be back in an hour.” The second friend walked away, and our Hero then went about working further on the Plunkle case.
About an hour later the second friend came back. “Here is your Boondit” the second friend said. “Thank you!” said our Hero, who then ran to find his third friend. “Here is a Boondit for you!” our Hero said, handing it over to the third friend. “Many thanks” said the third friend. “I will be back in an hour.” The third friend left, and our Hero went about finishing up the Plunkle case.
About an hour later the third friend appeared. “Here is your Plunkle”, the third friend said. “Oh, Thank you so VERY much” said our excited Hero. “I now have a Plunkle!”. Our Hero then proudly displayed the new Plunkle in a shiny new box.
The End.
Categories: Boring JavaScript Javascript
thevirtuoid
Web Tinkerer. No, not like Tinkerbell.
Creator of the game Virtuoid. Boring JavaScript. Visit us at thevirtuoid.com
Leave a Reply