Promises in JavaScript: A Primer

The following article covers a brief introduction to the concept of Promises. Promises are new-ish to JavaScript (introduced in ES6), and often misunderstood. The concept is basically a repurposing of familiar ideas in fancy branding.
Promises are a way to execute asynchronous code. Because JavaScript is a single threaded language, tools have to be created for this to happen since it doesn’t happen natively.
I’ll go over two detailed examples of what a promise can look like, how .then statements are chained together, and what causes a .catch to trigger and where it can trigger. The last topic will be the order of execution when promises are executed in multiple lines of code and what a successful promise resolution versus what a failed promise looks like from an external API.
How Asynchronous Code Is Different
Synchronous code is easy to understand. It’s much like writing itself.
I’m writing this line first. And now it’s read first.
Whoop, we’re here now. This line is executing now.
And so on.
And so forth.
But with asynchronous code, the code files are more like recipes. Read a little, measure, chop, and add more garlic… There are instructions, actions, and through text, the lines may start off as read in order, but different processes take longer than others. All that said, at no time does the application or dinner process stop because a server response or shrimp skewer takes longer than expected to complete.
The Anatomy of a Promise
A promise is an object that represents the eventual fulfillment of an asynchronous operation. It exists in three states:
- Pending: this is the starting place. The “promise” that at some point there will be an answer to this question even if the application continues to execute code further down in the file.
- Fulfilled/resolved: The promise was successfully resolved. The condition met was true or data was returned.
- Failed/rejected: The result of the promise if an error took place during the fulfillment of the promise.
Also, know these methods:
- .then: The JavaScript method used to handle a successful promise.
- .catch: How the errors are caught.
A new promise class is created with two parameters, resolve and reject. In this very basic example, there is a value. If the string value is correct it will resolve “correct” and if it’s incorrect then it will reject “error”. Simple.
Let’s resolve the promise.
And here’s what it looks like if the conditional statement is false.
That is incredibly basic and not a likely use case for promises.
Avoiding Callback Hell
Callback hell: An ambiguous yet descriptive term. Too many callbacks. Deep nesting. The functionality usually isn’t compromised but readability is a nightmare and that tends to compromise functionality especially when it comes to code updates especially when additional engineers are working on it.
The image above is the beginning of callback hell (from my article 3 Types of Asynchronous Programming). If you google callback hell there are many many worse images that can’t be included in this article for copy write reasons.
The example above builds off of the first example. This function takes in a data structure and if it is in fact an array, it resolves the sum of its elements, if not then rejects the promise. The answer is console.log 29.
What if a string is passed in?
Passing in {e} will return the error as an error object which is useful in more advanced use cases.
Perfect, it works.
What if we want to take the sum, find the remainder after it’s divided by two then subtract 50? .thens can be chained and it will look like this. Keep passing data from one to the next and along we go.
And the console logs look like this:
But if there happens to be an error, such as an undefined variable being subtracted by one of those values, the error object will display.
Great example, but like the first one, also not async code.
Async Example — HTTP Requests
For this example, I’m using the Star Wars API. Here’s the code:
The console logs look like this:
But if the code changes ever so slightly to delayed 1/4 second rather than delayed 1 second:
The console.logs will look like this:
The console.logs look like this:
And here is an example of promise chaining when receiving data in the API request.
If a request was made to a bad API for example:
Then you could either console.log a specific message or the entire error object. The error object in this case looks like this:
Additional Learning
This was an incredibly brief and basic introduction to promises. The learning gets pretty heavy after this initial stop. For a deeper dive into the material, this a good place to look. Codingame is a site where you can start working with async code and promises for a more hands on learning experience.