DEV Community

Zen Oh
Zen Oh

Posted on

Guide about Promise and Async Await

Before talking about promise I will explore about why does it needed. I will use jQuery as example, because a lot of people are using this library for a long time. JavaScript is an asynchronous language by default, and it is different with C / C++ / Java that was synchronous by default. The problem with this behavior is that it will be hard for us to chain a series of asynchronous functions. Here is the example, you can try to run this code inside console of your browser if you want (make sure the website you visit use jQuery).

const githubIds = ['docker', 'kubernetes', 'kubesphere'];

$.getJSON({
  url: `https://api.github.com/users/${githubIds[0]}`,
  success: function (res) {
    console.log(1)
    console.log(res.login)
  },
  error: function (xhr) {
    console.warn('Error')
  },
});
$.getJSON({
  url: `https://api.github.com/users/${githubIds[1]}`,
  success: function (res) {
    console.log(2)
    console.log(res.login)
  },
  error: function (xhr) {
    console.warn('Error')
  },
});
$.getJSON({
  url: `https://api.github.com/users/${githubIds[2]}`,
  success: function (res) {
    console.log(3)
    console.log(res.login)
  },
  error: function (xhr) {
    console.warn('Error')
  },
});
Enter fullscreen mode Exit fullscreen mode

When you run this code, the order of log from the console will always randomized on every requests. This is because the callback from api call will be called based on how fast the response is received, not by order of when it is called. If you want to correct this, you have to write your code like this:

const githubIds = ['docker','kubernetes', 'kubesphere'];

$.getJSON({
  url: `https://api.github.com/users/${githubIds[0]}`,
  success: function (res) {
    console.log(1)
    console.log(res.login)
    $.getJSON({
      url: `https://api.github.com/users/${githubIds[1]}`,
      success: function (res) {
        console.log(2)
        console.log(res.login)
        $.getJSON({
          url: `https://api.github.com/users/${githubIds[2]}`,
          success: function (res) {
            console.log(3)
            console.log(res.login)
          },
          error: function (xhr) {
            console.warn('Error')
          },
        });
      },
      error: function (xhr) {
        console.warn('Error')
      },
    });
  },
  error: function (xhr) {
    console.warn('Error')
  },
});
Enter fullscreen mode Exit fullscreen mode

As you can see now the code become more cluttered when we want to chain those asynchronous functions. So here is how promise will help us to resolve this.

const githubIds = ['docker', 'kubernetes', 'kubesphere'];

function getGithubUsername(id) {
  return new Promise(function (resolve, reject) {
    $.getJSON({
      url: `https://api.github.com/users/${id}`,
      success: function (res) {
        resolve(res.login)
      },
      error: function (xhr) {
        reject('error')
      },
    });
  })
}

getGithubUsername(githubIds[0])
  .then(function (username) {
    console.log(1)
    console.log(username)
  })
  .then(() => getGithubUsername(githubIds[1]))
  .then(function (username) {
    console.log(2)
    console.log(username)
  })
  .then(() => getGithubUsername(githubIds[2]))
  .then(function (username) {
    console.log(3)
    console.log(username)
  })
  .catch(function (err) {
    console.warn('error catched:')
    console.warn(err)
  })
Enter fullscreen mode Exit fullscreen mode

Now the code will looks much cleaner than before. Then ES6 has cool features called async await that will make promise chain functions like this much better and easier to read. Here is how it is when implemented using async await.

const githubIds = ['docker', 'kubernetes', 'kubesphere'];

function getGithubUsername(id) {
  return new Promise(function (resolve, reject) {
    $.getJSON({
      url: `https://api.github.com/users/${id}`,
      success: function (res) {
        resolve(res.login)
      },
      error: function (xhr) {
        reject('error')
      },
    });
  })
}

async function getAllGithubUsernames() {
  try {
    const u1 = await getGithubUsername(githubIds[0])
    console.log(1)
    console.log(u1)

    const u2 = await getGithubUsername(githubIds[1])
    console.log(2)
    console.log(u2)

    const u3 = await getGithubUsername(githubIds[2])
    console.log(3)
    console.log(u3)
  } catch (e) {
    console.warn('error catched:')
    console.warn(w)
  }
}

getAllGithubUsernames()
Enter fullscreen mode Exit fullscreen mode

Now you can see that your code is nice and clean using async await features from ES6. Few things to take note about async await:

  1. You can only use await when it is inside async function. Async functions will always return a promise.
  2. When you want to use await to call a function, you have to make sure that the function you call return a promise. Otherwise it won't be working, if the function is callback function like the jQuery getJson example above you have to change it so it return a promise.

Top comments (0)