Tuesday, 2 May, 2017 UTC


Summary

We are using callbacks in javascript from its beginning days. We thought it great. We can pass a method as an argument to another. Wow! Is not it amazing? Yes, it is unless we use a lot of it. Let’s say we have two callbacks i.e. A and B. This B callback can not do anything unless A completes. The problem will be more when the number of callbacks increases. Your code becomes nested and more complicated to read. To solve this problem, we introduced promises. Now in ES7, we have async-await. We will also discuss them in a while. I made a quick example demonstrating all this in a GitHub Gist. You can preview the gist here.
JavaScript callbacks
Let’s see the below example of a callback. Here we are writing a method which will make one asynchronous get request and will pass the data to its callback. So It is simple.
getWithCallback(url, callback) {
  const xhr = new XMLHttpRequest();
  let response = null;
  xhr.addEventListener("readystatechange", function() {
    if (this.readyState === xhr.DONE) {
      response = this.responseText;
      if (response) {
        response = JSON.parse(response);
        callback(false, response);
      }
    }
  });
  xhr.open("GET", url, true);
  xhr.send();
  xhr.onerror = function(error) {
    callback(true, {
      error: "Some error"
    })
  }
}
Now we will see the implementation of using this method. Here we will attach one click listener to a method and will use the above method to get the data. We will definitely not consider the below example as callback hell. If you are wondering about the below API link. It’s actually taken from my angular 4 tutorials.
const buttonCallback = document.querySelector('#buttonCallback');
const link = 'https://api.github.com/search/users?q=location:delhi';

buttonCallback.addEventListener("click", () => {
  getWithCallback(link, (err, data) => {
    if (!err) {
      console.log(data);
    }
  });
});
Now let’s see the problem, if we add another get request using the getWithCallback method, our code will be nested and hard to read.
buttonCallback.addEventListener("click", () => {
  let res = {};
  getWithCallback(link1, (err, data) => {
    if (!err) {
      res.data1 = data;
      getWithCallback(link2, (err, data) => {
        if (!err) {
          res.data2 = data;
          console.log(res);
        }
      });
    }
  });
});
Do you see that? This is called callback hell. Yes, obviously it is. I have written this example, still for me it’s hard to understand what’s going on. Now imagine in a production code, it is a real mess. So we came up with promises.
JavaScript promise – Covert callbacks to promises
I have seen a lot of developers who use promise a lot but never write them for their asynchronous methods. Here will convert our getWithCallback method to return a promise, which will be essentially resolved in the implementation.
getWithPromise(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    let response = null;
    xhr.addEventListener("readystatechange", function() {
      if (this.readyState === xhr.DONE) {
        response = this.responseText;
        if (response) {
          response = JSON.parse(response);
          resolve(response);
        }
      }
    });
    xhr.open("GET", url, true);
    xhr.send();
    xhr.onerror = function(error) {
      reject({
        error: "Some error"
      })
    }
  });
}
As you can see here we changed our code a little bit. We are returning Promise. Now let’s see the use case where we will be doing two subsequent get requests using this promise. Promise solves a problem. It gives a nice abstraction to avoid the callback hell. Your code readability also improves. Let’s see how to use our new promise returning method.
buttonPromise.addEventListener("click", () => {
  getWithPromise(link1).then(data1 => {
    console.log(data1)
    return getWithPromise(link2);
  }).then(data2 => {
    console.log(data2);
  }).catch(error => {
    console.log(error);
  });
});
We have only one catch block to grab our errors. This code is much cleaner. At this point, it might seem that it is the best solution available. I was also kind of obsessed with Promises.
The Async-Await Game
But with the introduction of ES7, now we have async-await. I would like to remind you that async-await does not make you independent of javascript promises. It is architected upon the present promise implementation of javascript. You can not fly away from promises. Still, you need to write promises. But async-await brings new joy to our codebase. It changes the way we consume promises. So let’s introduce a new method. Here we will use async and await. 
Few rules to write async-await
  1. The keyword async must be there in front of your method
  2. You can not use await alone. It must be inside async method.
  3. Async-await only makes your code look synchronous. Nothing else!
Let me see some async-await code
It is a good time to understand how they work.
const logWithAsync = async () => {
  let data1 = await getWithPromise(link1);
  let data2 = await getWithPromise(link2);
  console.log(data1, data2);
  return "done";
};
It does the same thing as the above two problems. But as you can see it is much cleaner. But how will I grab the errors here? So we can use our forgotten hero in javascript that is try-catch block.
const logWithAsync = async() => {
  try {
    let data1 = await getWithPromise(link1);
    let data2 = await getWithPromise(link2);
    console.log(data1, data2);
  } catch (err) {
    console.log(err);
  }
};
Is not it great? We can also use Promise.all here in the async-await.
const logWithAsync = async () => {
  try {
    let data = await Promise.all([getWithPromise(link1), getWithPromise(link2)]);
    console.log(data);
  } catch (err) {
    console.log(err);
  }
};
As you can understand that you can use async-await wherever you have promise. It just changes how you consume promises. You do not need to have back to back then methods.
If you are newbie and can not figure out what’s going on here, you should probably go through this.
Free Email Updates
Get the latest content first.
We respect your privacy.
The post A tour from JavaScript Callback to Promise to Async-Await appeared first on Apply Head.