???? JavaScript Visualized: Promises & Async/Await
ANKIT SINGH
Senior inside Sales @YHills | B2B | B2C | Customer Success |Data-Driven Sales Analyst | Expert in CRM, Sales Forecasting & Market Insights|| Crafting Unique Brand Voices ||
JavaScript Visualized (7 Part Series)
If you haven't read my previous post on the JavaScript Event Loop yet, it may be useful to read that first! I'll be covering the event loop again assuming some basic knowledge about the call stack, Web API and the queue, but this time we'll also be covering some exciting extra features ??
??? JavaScript Visualized: Event Loop
If you're already somewhat familiar with promises, here are some shortcuts to save you some precious scrolling time.
Introduction
When writing JavaScript, we often have to deal with tasks that rely on other tasks! Let's say that we want to get an image, compress it, apply a filter, and save it ??
The very first thing we need to do, is get the image that we want to edit. A getImage function can take care of this! Only once that image has been loaded successfully, we can pass that value to a resizeImage function. When the image has been resized successfully, we want to apply a filter to the image in the applyFilter function. After the image has been compressed and we've added a filter, we want to save the image and let the user know that everything worked correctly! ??
In the end, we'll end up with something like this:
Hmm... Notice anything here? Although it's... fine, it's not great. We end up with many nested callback functions that are dependent on the previous callback function. This is often referred to as a callback hell, as we end up with tons of nested callback functions that make the code quite difficult to read!
Luckily, we now have something called Promises to help us out! Let's take a look at what promises are, and how they can help us in situations like these! ??
Promise Syntax
ES6 introduced Promises. In many tutorials, you'll read something like:
"A promise is a placeholder for a value that can either resolve or reject at some time in the future"
Yeah... That explanation never made things clearer for me. In fact it only made me feel like a Promise was a weird, vague, unpredictable piece of magic. So let's look at what promises really are.
We can create a promise, using a Promise constructor that receives a callback. Okay cool, let's try it out!
Wait woah, what just got returned?
A Promise is an object that contains a status, ([[PromiseStatus]]) and a value ([[PromiseValue]]). In the above example, you can see that the value of [[PromiseStatus]] is "pending", and the value of the promise is undefined.
Don't worry - you'll never have to interact with this object, you can't even access the [[PromiseStatus]] and [[PromiseValue]] properties! However, the values of these properties are important when working with promises.
The value of the PromiseStatus, the state, can be one of three values:
领英推荐
Alright this all sounds great, but when is a promise status "pending", "fulfilled" or "rejected"? And why does that status even matter?
In the above example, we just passed the simple callback function () => {} to the Promise constructor. However, this callback function actually receives two arguments. The value of the first argument, often called resolve or res, is the method to be called when the Promise should resolve. The value of the second argument, often called reject or rej, is the value method to be called when the Promise should reject, something went wrong.
Let's try and see that gets logged when we invoke either the resolve or reject method! In my example, I called the resolve method res, and the reject method rej.
Awesome! We finally know how to get rid of the "pending" status and the undefined value! The status of a promise is "fulfilled" if we invoked the resolve method, and the status of the promise is "rejected" if we invoked the rejected method.
The value of a promise, the value of [[PromiseValue]], is the value that we pass to the either the resolved or rejected method as their argument.
Fun fact, I let Jake Archibald proofread this article and he actually pointed out there's a bug in Chrome that currently shows the status as "resolved" instead of "fulfilled". Thanks to Ankit singh Chauhan it's now fixed in Canary! ??????
Okay so, now we know a little bit better how to control that vague Promise object. But what is it used for?
In the introductory section, I showed an example in which we get an image, compress it, apply a filter, and save it! Eventually, this ended up being a nested callback mess.
Luckily, Promises can help us fix this! First, let's rewrite the entire code block, so that each function returns a Promise instead.
If the image is loaded and everything goes fine, let's resolve the promise with the loaded image! Otherwise, if there was an error somewhere while loading the file, let's reject the promise with the error that occurred.
Let's see what happens when we run this in the terminal!
Cool! A promise got returned with the value of the parsed data, just like we expected.
But... what now? We don't care about that entire promise object, we only care about the value of the data! Luckily, there are built-in methods to get a promise's value. To a promise, we can attach 3 methods:
The .then method receives the value passed to the resolve method.
The .catch method receives the value passed to the rejected method
Finally, we have the value that got resolved by the promise without having that entire promise object! We can now do whatever we want with this value.
FYI, when you know that a promise will always be resolved or always be rejected, you can write Promise.resolve or Promise.reject , with the value you want to reject or resolve the promise with!
Next part soon .............