Promises, Promises: An Introduction to Asynchronous JavaScript

For beginning learners of Javascript there are few concepts more daunting and head-spinning than the concept of ‘asynchronous’ functionality.

My prior experience to jumping headfirst into the ocean of JavaScript was in Ruby—a language our instructor continually described as ‘so friendly!’ Ruby’s appeal for beginning coders is how well it illustrates many of the tenets of object-oriented-programming while being a bit more user friendly and readable (and with great error handling).

Who doesn’t love a good Ruby error message?

JavaScript can feel like a whole other world, especially when it comes to synchronous versus asynchronous functionality.

Ruby, for the most part, feels like it handles code with pure synchronicity—code reads from the top to the bottom, left to right, executing in an orderly, predictable fashion. Unless it runs into a block, of course—perhaps something like an API call. Then our code grinds to a halt to handle that request.

For example, when relying on external servers, whether they belong to Google or are a Ruby on Rails backend API you built yourself, it doesn’t make sense to put a stop on your local code while waiting for a response. There are many things in this world we cannot control, the speed of an external server response is but one of them.

Asynchronous functionality can feel foreign at first, but when we break down how it works, we find that it’s really very intuitive to how we as humans already process daily tasks.

The much-loved example of this is making a large, complicated meal.

For, say, Thanksigiving, you wouldn’t prepare your meal by putting in your turkey and then waiting for it to cook entirely before tackling the next dish. If each dish were handled like this, at the end of many hours, you’d have a complete, but cold meal.

You have to multitask to get it done well, and JavaScript has a very clever way fo doing this through its integration of asynchronous functions in callbacks and promises.


While callback functions are a form of async functionality, in modern JavaScript the best example of async handling comes in the form of promises.

Promises are essentially a placeholder for a value that the code does not yet have at the time it’s created. It, therefore, allows you to chain handlers that will work with the results success value or failure.

My favorite description of a promise from MDN describes it as feeling “like Schrödinger’s cat in action.” Much like the iconic thought experiment, a promise is nothing more than the idea that a response will be generated eventually, and at the point we receive the Promise, we don’t know the outcome of the response. A promise is both the completion and failure of a request at the same time.

From ‘The Adventures of Schrödinger’s Cat

Promises can have one of three states:

  • Pending: this is the initial state, showing that the promise has been neither fulfilled nor failed
  • Fulfilled: the operation was completed successfully
  • Rejected: the operation has failed and comes with an error

Basic Use of a Promise

So, let’s see the promise in action in JavaScript.

What we’re talking about when we talk about async functionality is well illustrated by the use of the fetch function. Fetch functions take one argument—the path the resource you’re trying to fetch.

In the code above, we have a basic example of the use of a fetch . We’ve declared and assigned a variable that contains the url to which we’ll be making our request. In the body of the function fetchData , we’re not only calling our fetch—we’re also chaining .then() functions that are used to handle actions for the settled promise.

We’re telling the code—once the the promise has been fulfilled, parse the response into JSON data, and then log that response.

But let’s also look at exactly how this function is running asynchronously. When we run this code, it will first log in our console “Started Running.” But what will we see logged next? “Finished Running”! This is because while the code has made the fetch request, it continues to move on to the console.log("Finished Running") on line 12. Then, once the promise has been fulfilled, it will convert the response into JSON, then log it for us to review.

The non-magical magic of asynchronicity is that it allows for multiple things to happen at once. While our code is moving on and logging “Finished Running” it’s still attending to the promise, and once fulfilled it’s moving through our chained .then() functions using the results of that promise.

We can even chain a .catch() function which will allow us to error handle if our promise is rejected

In programming, where we’re used to immediate feedback, asynchronous functionality can feel foreign at first. But the results speak for themselves. Async code and async JavaScript allows for dynamic code that works smarter that better mirrors the way humans work.

It follows one of my personal favorite goals of programming—efficiency!

Software Engineering Student