Understanding JavaScript promises & asynchronization using real life examples

Sun Apr 01 2018

Paul Shan

It has been almost 6 years now that I have been coding/programming in JavaScript with various organizations. During the period I’ve noticed that JavaScript promises are one of the most commonly used thing in all kind of codebases; and this is also one of the hardest things for a newbie to understand in general.

For example, today I was explaining promises to one of the newbies in my company and what can be better way than to explain promises in layman’s language with help of day-to-day examples.

This learning nugget talks about asynchronous calls and handling promises in vanilla/native JavaScript with real life examples. This post is for beginners, especially for those who find it difficult to understand promises.

What is a promise in JavaScript?

Promises are something, which can get your job done, after completion of a certain task with uncertain timelines. Let’s forget about big terms like asynchronous for now; I will talk about them later.

The problem

Suppose some guests are going to visit you today at 7pm and you have already told them that you are going to cook for them.

You come home from office at 5pm, freshen up and enter kitchen at 5:30pm. You still have 1.5 hours to finish up your cooking; that’s not a bad amount of time.

You are half way through preparing your chicken curry, when at 6:15pm you reach out to add salt and realize you don’t have even a bit of salt at home. Now what to do? You also have to prepare some lemonade for them. You just can’t go out and buy salt and then come back, finish your curry then prepare lemonades; cause you don’t have that much time.

The solution

What you should ideally do is; ask your roommate (your friend, girlfriend or whoever stays with you) to go out and bring you some salt.

Now this way you can keep preparing other things like lemonade and when your girlfriend comes back with salt, you add salt in your chicken curry.

This way you were not blocked at all; you continued with your ongoing tasks and someone else performed your salt bringing sub-task separately and whenever she returned, you simply need to add salt in your chicken curry. This means less time consumption and early wrap up.

The same scenario in JS code

comeBackFromOffice();
freshenUp();
gotoKitchen();
var chickenCurry = startMakingChickenCurry();

// now you realised you don't have salt
var saltBringingPromise = girlfriend.sendToBringSalt();
saltBringingPromise.then(function(salt){
  // this will run when she comes back with salt
  chickenCurry.put(salt);
});

prepareLemonade();

Let’s interpret the code line by line.

In the first line you came back from office. Then you took a shower. Then you went to the kitchen. Then you started preparing the chicken curry.

We are holding the chicken curry in the variable chickenCurry. So, when you realized there is no salt, you asked your girlfriend to go and get one packet of salt girlfriend.sendToBringSalt(). Now this thing (not the girlfriend, but the scenario of bringing salt) is completely out of your current control. You don’t know her exact time of return. So you have used the .then() function which runs the code inside it after the promise is resolved; or in other words your girlfriend is back with salt.

So by using .then(), you have notified JavaScript to run a certain piece of code after the work is done. So JavaScript will remember this command and will continue to prepareLemonade(). So the code inside .then() will not run before prepareLemonade(), rather JS will execute prepareLemonade() immediately and after prepareLemonade() is done, chances are you might rest a bit on your couch when suddenly your girlfriend comes back with salt (if you notice the parameter of the callback in .then is salt, so basically promise brings you some data) and after that chickenCurry.put(salt) will be executed. Getting a hint now how exactly is it working?

$.ajax() - a known promise

We are generally very familiar with jQuery. Many of us have used $.ajax() or similar functions like $.get(), $.post() etc to call a server.

These apis returns a promise object; thus has a .then() function with it.

var ajaxObject = $.ajax("http://my-server.com/api/some-calls");
ajaxObject.then(function (response) {
  console.log(response);
});
console.log("I am outside then function");

If you run the code mentioned above, it will print I am outside then function first. Because you have just fired the $.ajax() function and the response from your api is not there yet. Whenever the server responds and your ajax receives it; then it will automatically run the code written in .then().

How to create a promise?

$.ajax() is something inbuilt in jQuery. But can we create a promise all by ourselves? Yes obviously you can. ES6 came up with native Promise support in JavaScript. Here is a snippet:

console.log("I am first");
var prom = new Promise(function(resolve){
  setTimeout(function () {
    resolve(100);
  }, 5000);
});
prom.then(function (value) {
  console.log("I am in then with ", value);
});
console.log("I am second");

When you run the above snippet, it will first print I am first. Once we have created a promise, you can check the syntax of creating a promise using the Promise constructor. So the Promise constructor takes a function as a parameter and that function has a resolve as its first parameter. You do whatever you want to do inside that promise constructor, but whenever you call the function resolve(), JavaScript will consider this promise as done and eventually will call functions which were given through .then().

Anyway, so the entire output of this will be as follows:

I am first
I am second
I am in then with 100 // after 5 seconds

So as you can see, I am second is printed before I am in then .... Because the I am in then ... was in then and the code wouldn’t have executed until and unless the promise is resolved. This was done after 5 seconds and do you know from where the value 100 came? It was the value you attached while calling resolve(100).

Similarly, in case of $.ajax, assume that resolve(apiResponse) was called internally when the response from api server was received.

reject and catch

Till now you have seen only the happy flow; where only the expected thing was done.

But our life doesn’t always run with the happy flow. Suppose the shop was closed and your girlfriend couldn’t get you salt for the curry. Then what? Probably you will end up ordering some dishes from outside.

What if your girlfriend met with a road accident while bringing salt (although I wish these kind of things never happen to you, your gf or anyone else)? Then she won’t return home to inform you; rather you will get a call from police or someone else and rush to the hospital; rather than doing anything for your guests.

These two scenarios are also possible while developing JavaScript promises. Our favourite .then() actually takes two functions inside it. The second function is used to handle the reject, or in our example when your girlfriend will come back with the information that she could find salt.

comeBackFromOffice();
freshenUp();
gotoKitchen();
var chickenCurry = startMakingChickenCurry();

// now you realised you don't have salt
var saltBringingPromise = girlfriend.sendToBringSalt();

saltBringingPromise.then(function(salt){
  
  // this will run when she comes back with salt
  chickenCurry.put(salt);
}, function(){

  // no salt found
  chickenCurry.putInDustbin();
  orderOnline();
});

prepareLemonade();

See, we have provided .then() with another function in it to handle the rejected scenario.

So how to handle this while making our promise? Refer to the extended snippet below:

console.log("I am first");

var prom = new Promise(function(resolve, reject){
  setTimeout(function () {
    if(Math.random()*10 > 5 ){
      resolve(100);
    } else {
      reject(20);
    }
  }, 5000);
});

prom.then(function (value) {
  console.log("I am in then with ", value);
}, function (value) {
  console.log("I am rejected with ", value);
});

console.log("I am second");

Actually, the function parameter in Promise constructor also has a second parameter called reject, using which you can reject a promise. I am rejecting or resolving the above promise with a random chance. So as an output, in the last line, you will either find I am in then with 100 (when the promise is resolved) or I am rejected with 20 (when the promise is rejected).

Now let’s code catch in both the examples mentioned above.

comeBackFromOffice();
freshenUp();
gotoKitchen();
var chickenCurry = startMakingChickenCurry();

// now you realised you don't have salt
var saltBringingPromise = girlfriend.sendToBringSalt();


saltBringingPromise.then(function(salt){
  // this will run when she comes back with salt
  chickenCurry.put(salt);
}, function(){
  // no salt found
  chickenCurry.putInDustbin();
  orderOnline();
}).catch(function (err) {
  // she met an accident and police called you
  rushToHospital();
});
prepareLemonade();

Just like .then(), we’ve again attached another thing called .catch(). This is to handle unexpected errors. Now when exactly do things come into catch? Refer to our old promise creation below which introduced catch as well.

console.log("I am first");

var prom = new Promise(function(resolve, reject){
  setTimeout(function () {
    var aRandomNumber = Math.random()*10;
    if(aRandomNumber < 1){
      throw new Error("Nah, I don't like that");
    }
    if(aRandomNumber > 5 ){
      resolve(100);
    } else {
      reject(20);
    }
  }, 5000);
});

prom.then(function (value) {
  console.log("I am in then with ", value);
}, function (value) {
  console.log("I am rejected with ", value);
}).catch(function(){
  console.log("Error occured");
});

console.log("I am second");

So if you throw an Error somewhere in your promise, your functions in .then() will never be executed. It will come all the way down to your catch.

The chaining of promises

The main advantage of promise is the ability to chain them. Often while writing code we find a scenario where one task is dependent on the other and this way we have a chain of dependent works.

Suppose, you want to retrieve the friend list of the currently active user on Facebook. So, first you need to know who active on Facebook currently. Then your requirement is to get the Facebook ID etc. of that user. Then your next step is to call Facebook apis to get his friend list; and similar dependent things can go on.

Now the problem is, all these tasks are asynchronous and takes their own time. You just cannot write one after another until and unless you use promise. Refer to this code snippet below to know more.

function getCurrentUser() {
  // return a promise from here
}

function getUserFacebookId(userId) {
  // return a promise again as here also youare gonna call your server
}

function getFacebookFrieldList(fbUserId) {
  // return a promise which will later resolve with facebook friendlist
}

function myTask() {
  console.log("I am starting here");
  getCurrentUser()
  .then(function (user) {
    return getUserFacebookId(user.id);
  })
  .then(function (fbId) {
    return getFacebookFrieldList(fbId);
  })
  .then(function (friends) {
    friends.forEach(function (friend) {
      console.log(friend.name);
    });
  });
}

Conclusion

Though I have given an example where I explained that tasks in promises goes on separately without blocking you; but in real life it is not always exactly like that. That’s more low level and deeper stuff and you don’t need to know them at this very moment. Concurrency and parallelism is something we can understand later.

But promises are really awesome and has a key role to play in making JavaScript asynchronous and saving the codebase from callback hells. In ES2017 of ES8, we also had something called async await to make your code more readable and easy to write; but in the heart of this, there is a combination of Generators and Promises.

I tried my best to make this post easier to read for beginners, but if you still can’t understand something, feel free to post a comment; I will try to answer as soon as possible.

SHARE THIS ARTICLE

post-thumbnail
Today everyone knows the importance of a lightning-fast website and how the speed impacts the conversion rate of a business. Today, everyone wants the site to be a PWA so that the mobile users can have an app-like experience with the website because, for the majority of the merchants, the customers come through mobile devices.
Tue Apr 20 2021
post-thumbnail
Here we are going to see how you can manage backup and restore of Postgres database with docker.
Thu Sep 03 2020
post-thumbnail
Image sliders or carousels always have increased the UI attraction of websites and they are pretty useful for reflecting the major roles/products too. In case, I am having a website that sells tee-shirts,
Mon Apr 30 2018

About VoidCanvas

This blog was created out of hobby and talks mostly about technology, web development, JavaScript, NodeJS and related topics. Thank you for reading my blog.

Copyright 2022 - www.voidcanvas.com

Popular Articles

Authentication using Google's oAuth api with node.js

Thu Mar 10 2016

OAuth authentications are pretty popular now a days and another thing which is popular is JavaScript. This article shows how to plugin google’s oAuth api for authentication in your own node application.

CSS3 Loader Snippet Collection: (Part 2 - Squares)

Sat Mar 01 2014

This is a continuation of my CSS3 loader snippet collection series. I've provided spinning css3 animation loader in the part 1 of this series and here in part 2, I'm providing various square type loading