JavaScript Promises

Praveen Gaur
6 min readFeb 23, 2019

--

Theoretically, JS promises are no different than the real life promises — when coupled with result oriented conditions.

Promise is an action which guarantees a result in future, the result could be the expected one(positive) and if anything goes wrong, the result will be something which was not anticipated(negative). So, while doing the promise we also close on the conditions — what if:

  1. If Mike is able to clean his room(fulfilling the promise condition): He goes out for football !!
  2. But what if he does not clean(failing to complete the promise condition): he needs to do the laundry.

NOTE: In terms of programming, this behavior represents the asynchronous behavior. Mike is expected to clean his room synchronously but the conditional actions(callbacks) will be executed in future(whether he goes out to play or he does the laundry).

Assuming, ‘Room Cleaning’ is an action which produces success or failure results. Then ‘Football’ and ‘Laundry’ are the asynchronous handlers which are waiting for the ‘Room Cleaning’ action to finish. And depending upon the result is success or failure, either the ‘Football’ or ‘Laundry’ handlers will be executed, ASYNCHRONOUSLY!!

Before we go in to much of the technical details, if you are not clear on:

Essentially promise(s) is the antidote to the antipattern Callback-hell. It’s a new way to introduce asynchronous callbacks without have to deal with ‘pyramid of doom’.

Some basics:

  1. A promises has to has the main action, in our example it was ‘Room Cleaning’. Technically, this main action is a function, called executor.
  2. Now, the executor can produce either the successful or failure results. The handlers — ‘Football’ and ‘Laundry’ are the asynchronous callback functions, registered using then & catch — will see in more details.
  3. As developer, you first need to define the executor & handler functions.
  4. Then promise(s) comes in to play — Promises is just the way how as developers should arrange all these dependencies in code more cleanly.
  5. Promise(s) is JS object provided by the standard implementation(after ES6) to arrange all these dependencies. A new promise is created using the Promise constructor.

Now, delve in to some code :)

Example 1: writing a simple Promise

  1. roomCleaning is the executor function here — which is executed synchronously by JS.
  2. It accepts 2 arguments resolve & reject, these are just the placeholder variables which are initialized by JS itself. Resolve represents the success, while the reject represents the error scenario. These handlers are called asynchronously, once the executor finishes.
  3. At line 10, new promise is created by passing the executor function as an argument to the Promise constructor. This is how you create a new Promise. New instance is stored in promise_1 variable.
  4. At line 11, promise_1.then is the method which accepts the success handler method as the argument. Whatever method is passed here will be called when resolve is called from executor function.
promise_1.then((resolveValue)=>{//Success handler, Footballconsole.log(`Success handler - room claened successfully, football time!!`);console.log(`resolveValue: ${resolveValue}`);});

Callback passed in then also accepts an argument(resolveValue), when you call resolve(num) in the executor function, the value of num is passed as the value of resolveValue argument.

5. Similarly, the callback provided to catch function is executed by JS when reject(error) is called.

Ideally, the value passed in reject should represent an error object, so that JS passes this object to the catch handler — there developers should handle the error.

Example 2: multiple handlers can be attached to the same promise

Multiple handlers can be attached to the same promise, this results in multiple asynchronous call backs registered to be executed when resolve/reject is called.

All the callbacks are executed but in same order as registered:

In the above example, there are two handlers registered for both — resolve and reject. Both the handlers are executed in the same order as registered.

Promise States: Pending, Reject, Resolve

Let’s quickly talk about the Promise states. As we know that Promises are the JS provided objects that wraps and do the heavy lifting work of orchestrating the asynchronous calls.

But how developers would come to know the current state of a promise, that is if the executor is finished or if it is call one of the handlers. For that Promise object exposes the state property. Possible values:

  1. Pending: If the executor is currently in progress.
  2. Resolved: If the executor is finished executing and resolve method is called.
  3. Rejected: If the executor is finished executing and reject method is called.
Promise States

When the executor finishes the job, it should call one of the functions that it gets as arguments:

  • resolve(value) — to indicate that the job finished successfully:
  • sets state to "fulfilled",
  • sets result to value.
  • reject(error) — to indicate that an error occurred:
  • sets state to "rejected",
  • sets result to error.

Note:

  1. If a resolve is called in executor. Calling the resolve again, will have no impact — resolve handler will be called only once.
  2. If a reject is called in executor. Calling the reject again, will have no impact —reject handler will be called only once.’
  3. Once the reject/resolve is done execution — promise is said to be settled. Settled is not a formal state but a name given to identify if the promise is done with executor and handler execution.

Promise Chaining:

Here is some twist in story, suppose you want to chain the conditions. For instance:

  • If Mike is able to clean the room, then he goes for football.
  • In football match, if he makes a goal, then as reward he gets a chance to visit the music concert. If he does not makes a goal then he cleans his dog.
  • If he is not able to clean the room then he does the laundry.
  • If he is not able to finish the laundry either then he has to clean his dog.
  • But if he is able to clean the laundry then he goes for concert.

Now, you see the conditions are producing more conditional actions. Technically, asynchronous callbacks(Football & Laundry) are again producing additional asynchronous callbacks(MusicConcert & DogCleaning). To serve this purpose, Promises can return new promises — that is called Promise Chain.

Promise Chaining

So, essentially: A promise:

  • A inside executor function, you can call the resolve method for success scenarios.
  • Or you can call the reject method for error scenarios.
  • And if the output of this asynchronous function should be a input to another asynchronous function then, return a new Promise…..
Promise Chaining Workflow

Important thing to note: Look at the image above, if you return new Promise(s) both from a resolve and reject handler, though you are returning two different instances(using new keyword) but they still point to the same Promise instance.

This will be clear from the code example below:

If you execute the above code in console, you will see something like:

Success

OR something like:

Error

Notice that promise the individual promise instances are returned from the reject and resolve handlers of the parent promise. But still both the Error_success & Erro_error are printed, because the new promises returned from the handlers are actually point to the same promise instance.

If that does not make sense, then read this again:

Important thing to note: Look at the image above, if you return new Promise(s) both from a resolve and reject handler, though you are returning two different instances(using new keyword) but they still point to the same Promise instance.

And have a look at the promise chaining workflow image.

I believe as a programmer this is all you would need to know to understand Promises. If you understood this, you are all set to go & start doing Promises !!

Happy Coding !!

--

--