Async await

Before async await, we used promises and callbacks to handle the asynchronous code in javascript. While working with promises and callbacks you might have heard a term called callback hell. In simple terms, it happens when our code has too many nested callbacks.

To solve the callback hell, a new feature was introduced in ECMAScript 8 (2017) called async await. Async await is a new way to write asynchronous code in javascript.

So what is async await and how does it work?

1. async

To create an async function, async keyword should be added in front of function keyword.

Few points to remember:

Example:

async function sayHello(say) {
  return 'hello';
}

// To handle success & failure
sayHello()
  .then(console.log) // success
  .catch(console.log); // failure

2. await

await keyword can only be used inside async function, except for the top-level await.

Few points to remember:

Example:

async function fetchPokemon() {
  try {
    const pokemon1 = await fetch('https://pokeapi.co/api/v2/pokemon/1');
    const pokemon2 = await fetch('https://pokeapi.co/api/v2/pokemon/2');

    const response1 = await pokemon1.json();
    const response2 = await pokemon2.json();

    console.log(response1.name + ' ' + response2.name);
  } catch (error) {
    console.log(error);
  }
}

fetchPokemon(); // logs "bulbasaur ivysaur"

Async await works as if the code were synchronous, but without blocking the main thread. Read my previous post to understand more about main thread and event loop.

Let's see the same example using promise based fetch API.

Example:

function fetchPokemon() {
  fetch('https://pokeapi.co/api/v2/pokemon/1')
    .then((response1) => {
      return response1.json().then((response1) => {
        return fetch('https://pokeapi.co/api/v2/pokemon/2').then((response2) => {
          return response2
            .json()
            .then((response2) => {
              console.log(response1.name + ' ' + response2.name);
            })
            .catch((error) => {
              console.log(error);
            });
        });
      });
    })
    .catch((error) => {
      console.log(error);
    });
}

// Fetch pokemon
fetchPokemon(); // logs "bulbasaur ivysaur"

The above code works as expected but it is hard to debug and becomes a non-maintainable code if we want to modify or extend the function.

GIF: this gif which explains async await in 7 seconds:

Disadvantages:

Fun fact: Async await is a syntactic sugar built on top of promises.

If you know javascript well then you might have already guessed that await calls then() method under the hood. Now you know why await only works with async functions.

Example:

var customThenFunz = () => {
  return {
    then: (resolve, reject) => {
      resolve('hello'); // resolve & reject are promise callback's
    },
  };
};

console.log(await customThenFunz()); // logs "hello"

In the above example, await calls the then() method returned by the customThenFunz function. One more point to remember is async await uses generators internally to pause and resume execution of the code.

Now we will write the above example using generators & promises to help us to understand how async await would be been implemented internally.

Before I proceed with implementation, let's try to understand the basics of generators.

Example:

A simple counter function to return the count until maxCount is reached.

function* counter(maxCount) {
  var i = 1;
  while (i <= maxCount) {
    yield i++;
  }
}

var iterator = counter(2);

console.log(iterator.next()); // logs {value: 1, done: false}
console.log(iterator.next()); // logs {value: 2, done: false}
console.log(iterator.next()); // logs {value: undefined, done: true}

Now we understood how generator function in javascript works, lets write our custom async await function.

To emulate async await we need to do the following:

We will name our custom function as customAsyncAwait. Input for customAsyncAwait function will be a generator function. Inside our customAsyncAwait function, we will create a generator object by calling the input when the customAsyncAwait function is invoked. A function called resolver() is used to handle iteration of the generator function which will be called recursively by passing the iterator object as an input. If the iteration is done, then resolve and return the value. If it fails throw an error which in turn resolves and return the error.

function customAsyncAwait(generatorFunz) {
  // create generator object
  const generatorObj = generatorFunz();

  function resolver(currentIteration) {
    // If the iterator object is done then return the value
    if (currentIteration.done) {
      return Promise.resolve(currentIteration.value);
    } else {
      return Promise.resolve(currentIteration.value)
        .then((value) => resolver(generatorObj.next(value))) // proceed with next iteration in generator
        .catch((error) => resolver(generatorObj.throw(error))); // throw an error
    }
  }

  return resolver(generatorObj.next()); // Start the iteration
}

// Fetch based generator
function* fetchPokemonGenerator() {
  try {
    const pokemon1 = yield fetch('https://pokeapi.co/api/v2/pokemon/1');
    const pokemon2 = yield fetch('https://pokeapi.co/api/v2/pokemon/2');

    const response1 = yield pokemon1.json();
    const response2 = yield pokemon2.json();

    console.log(response1.name + ' ' + response2.name);
  } catch (error) {
    console.log(error);
  }
}

// Call our custom async function
customAsyncAwait(fetchPokemonGenerator); // logs "bulbasaur ivysaur"

Final thoughts

Async await is an interesting topic and powerful feature in javascript. It helps us to write the asynchronous code more readable and maintainable. I hope in this post you have learned a little bit more about javascript. The custom async await function I wrote might not be how async await would have been implemented but you get the idea right how it works?.

Post a comment below if you have any questions. If you like the post share it. Thanks for reading till the end :)

Follow me on twitter for more web related things.

Join 305+ Readers

Sent out once every month. No spam 🤞