Step by Step: Promises in JavaScript

Written by Omar Mohammad|5 min read|
105 Views

If you’re someone who is new to the land of Javascript you will have most certainly heard of promises. They can be intimidating at first, but attempting to first understand what problem they solve in JavaScript goes a long way in helping you to understand the underlying concept.

Understanding Promises involves the following steps:

  1. Understanding blocking vs non-blocking program execution (async vs sync)
  2. Understanding what problem Promises solve and the need for having something like it.
  3. Understanding nature of Promises.

Blocking vs Non-Blocking

Javascript is often referred to as a single threaded programming language. This essentially means it has by design a single call stack and single memory heap. Which is a fancy way of saying that it can only execute a single line of code at a given moment. Unless the code execution of a line is finished, the execution control does not move onto the next line.

In Computer Science, this is referred to as Synchronous programming. As stated above, no two tasks can occur simultaneously. This means that if operation A takes ‘5’ seconds, the next operation B will only occur after ‘t+5’ seconds. We often call such a phenomenon as “Blocking” as it literally blocks or halts the execution flow in a program.

On the other side of the spectrum we have Asynchronous programming. As the name suggests, it states the opposite: Multiple operations can occur at the exact same time. This means if operation A is taking ‘5’ seconds to finish, the next operation B will not have to wait for ‘t+5’ seconds to start. Unsurprisingly we refer to this behaviour as “Non-blocking” as the execution flow is not stopped or made to wait for a certain task to complete.

Javascript by default is a Synchronous Programming Language. It is blocking in nature. This isn’t necessarily a bad thing because in most cases the operations we do through it are fast and don’t consume too much time.

On the other hand, some tasks like reading files, making calls to the server, etc take a good amount of time to execute and can block the execution of the program. Such tasks need to be handled asynchronously. Fortunately, JavaScript provides mechanisms through which you can easily write Asynchronous code.

Credit: https://www.vbatelemetry.com/vba-error-handling-track-events-custom-metrics-within-vba-projects/asynchronous-vs-synchronous/

Both Synchronous and Asynchronous operations have their own pros and cons. As simple rule of thumb in Javascript we stick to the default Synchronous behaviour and only switch to Asynchronous operations when the need for it arises. It might be tempting to assume that why not make everything Asynchronous? But this comes with its own pitfalls, the biggest being that you lose track of the sequence of operations in your own code.

Why we need Promises

There are three such mechanisms that make it possible for us to make Javascript behave Asynchronously. They are:

  1. Callback Functions
  2. Promise API
  3. Async Await

Callback Functions are simply Javascript functions you pass to another function to be run when the function is finished.

// Define Function
function GetUserInfoFromServer(user, callback) {
  // Fetching User Info operation (this takes time)
  callback(logUserInfo);
}

// Define the CallBack
function logUserInfo(info) {
  console.log(info)
}

// Executing Main Function
GetUserInfoFromServer('Omar', logUserInfo);

Without going too deep into callbacks(since it is not the topic of discussion here) we can for now suffice to say that they are a something of a hacky way to tell Javascript to perform Asynchronous operations. Using them is not objectively good or bad but they eventually become unmanageable in large scale applications and result in something we call Callback from Hell.

Promises aimed to solve some of the problems that came with Callbacks. With time as the web landscape drastically grew, the call for a proper way to manage Asynchronous operations gained more and more momentum. Eventually in 2015, as a part of the fresh ES6 Spec, we got our first taste of the Promise API. As Eric Elliot notes in this brilliantly comprehensive article, the evolution of Promises, how they came to be and the state they are in now.

What is a Promise?

So finally, what is a Promise?

According to the MDN Docs: “The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.”

In simple English, and to quote Eric Elliot again: “A promise is an object that may produce a single value sometime in the future.”

Let us try to break this down into bits:

A Javascript Promise,

  1. Is an Object
  2. It represents two things
    1. The status of an Asynchronous Operation, if it was completed successfully or failed?
    2. The result of that Async Operation

And that is a promise!

Lastly, since a Promise is an object, it can be instantiated using the new operator on the Promise Constructor.

const myPromise = new Promise((resolve, reject) => {
  // you can chose to resolve or reject your promise here
});

We will take a deeper look at the Promise Object in my next post: Diving Deep into Promises.

Loading...