Table of Contents:

  1. Introduction (callbacks, promises, async/await)
  2. Real world example — Currency Converter that is receiving asynchronous data from two API’s.

Just a note…

Along with writing this article, I have also created a YouTube video!
You can follow along and code while watching. I advise you to first watch the video and then code use the article as a guidance.

Link of the video: Learn Async/Await in This Real World Project

Introduction

Async/await is a new way to write asynchronous code. It is built on top of promises, therefore, it is also non blocking.

The big difference is that asynchronous code looks and behaves a little more like synchronous code. This is where all its power lies.

Previous options for asynchronous code were callbacks and promises.

Callbacks in action

setTimeout(() => {
  console.log('This runs after 1000 milliseconds.');
}, 1000);

Problem with callbacks The infamous Callback Hell

Nesting callbacks within callbacks will soon start to look like this:

Callback Hell

Callback Hell

The situation where callbacks are nested within other callbacks several levels deep, potentially making it difficult to understand and maintain the code.

Promises in action

const promiseFunction = new Promise((resolve, reject) => {
  const add = (a, b) => a + b;
  
  resolve(add(2, 2));
});

promiseFunction.then((response) => {
  console.log(response);
}).catch((error) => {
  console.log(error);
});

promiseFunction returns a Promise that represents the process of that function. The resolve function signals the Promise instance that it has finished.

Afterwards, we can call .then() and .catch() on that promise function:
then — Runs a callback you pass to it when the promise has finished.
catch — Runs a callback you pass to it when something went wrong.

Async Functions

Async function provide us with a clean and concise syntax that enables us to write less code to accomplish the same outcome we would get with promises. Async is nothing more than syntactic sugar for promises.

Async functions are created by prepending the word async before the function declaration like this:

const asyncFunction = async () => {
  // Code
}

Asynchronous functions can be paused with await, the keyword that can only be used inside an async function. Await returns whatever the async function returns when it is done.

This is the difference between promises and async/await:

// Async/Await
const asyncGreeting = async () => 'Greetings';

// Promises
const promiseGreeting = () => new Promise(((resolve) => {
  resolve('Greetings');
}));

asyncGreeting().then(result => console.log(result));
promiseGreeting().then(result => console.log(result));

Async/Await looks similar to synchronous code, and synchronous code is much easier to understand.

Now that we’ve covered the basics, let’s move onto our real world example!

Currency Converter

Project clarification and setup

In this tutorial, we will build a simple but educational and useful application that is going to improve your overall knowledge of Async/Await.

The program will take in currency code we want to convert from and currency code we want to convert to, as well as the amount of money. Afterwards, the program will output the correct exchange rate based on the data from the APIs.

In this application we’re going receive data from two asynchronous sources:

  1. Currency Layer https://currencylayer.com — You’ll need to sign up for free so you can use the API Access Key. This API will provide us with data needed to calculate exchange rate between currencies.
  2. Rest Countrieshttp://restcountries.eu/ — This API will give us information about where can we use the currency we just converted our money to.

For starters, create a new directory and run npm init, skip through all the steps, and install axios by typing npm i --save axios. Create a new file called currency-converter.js.

Firstly, require axios by typing: const axios = require(‘axios’);

Let’s dive into async/await

Our goal for this program is to have three functions. Not one, not two, but three asynchronous functions. The first function is going to fetch data about currencies. The second function if going to fetch data about countries. And the third function is going to gather that information into one single place and output it nicely to the user.

First function — Receiving Currency Data Asynchronously

We’ll create an asynchronous function that is going to take in two arguments, fromCurrency and toCurrency.

const getExchangeRate = async (fromCurrency, toCurrency) => {}

Now we need to fetch the data. With async/await, we can assign data directly to a variable; don’t forget to sign up and enter your own correct access key.

const getExchangeRate = async (fromCurrency, toCurrency) => {
  const response = await axios.get('http://data.fixer.io/api/latest?    access_key=[yourAccessKey]&format=1');
}

The data from the response is available under response.data.rates so we can put that into a variable just below response:

const rate = response.data.rates;

Since everything is being converted from the euro, below, we’ll create a variable called euro which will be equal to 1/currency we want to convert from:

const euro = 1 / rate[fromCurrency];

Finally, to get an exchange rate we can multiply euros by the currency we want to convert to:

const exchangeRate = euro * rate[toCurrency];

Finally, the function should look something like this:

Second function — Receiving Country Data Asynchronously

We’ll create an asynchronous function that is going to take currencyCode as an argument:

const getCountries = async (currencyCode) => {}

As we saw before, we are going to fetch data and assign it to a variable:

const response = await axios.get(`https://restcountries.eu/rest/v2/currency/${currencyCode}`);

We’ll then map over the data and return country.name for each:

return response.data.map(country => country.name);

Finally, the function should look something like this:

Third and final function — Merging it all together

We’ll create an asynchronous function that is going to take fromCurrency, toCurrency, and amount as arguments:

const convert = async (fromCurrency, toCurrency, amount) => {}

First, we get the currency data:

const exchangeRate = await getExchangeRate(fromCurrency, toCurrency);

Second, we get the countries data:

const countries = await getCountries(toCurrency);

Third, we save the converted amount to a variable:

const convertedAmount = (amount * exchangeRate).toFixed(2);

Finally, we output it all to the user:

return `${amount} ${fromCurrency} is worth ${convertedAmount} ${toCurrency}. You can spend these in the following countries: ${countries}`;

All of that put together should look like this:

Adding try/catch to deal with error cases

We need to wrap all our logic in try, and catch the error if there is one:

const getExchangeRate = async (fromCurrency, toCurrency) => {
  try {
    const response = await       axios.get('http://data.fixer.io/api/latest?access_key=f68b13604ac8e570a00f7d8fe7f25e1b&format=1');
    
    const rate = response.data.rates;
    const euro = 1 / rate[fromCurrency];
    const exchangeRate = euro * rate[toCurrency];
    
    return exchangeRate;
  } catch (error) {
    throw new Error(`Unable to get currency ${fromCurrency} and  ${toCurrency}`);
  }
};

Repeat the same for the second function:

const getCountries = async (currencyCode) => {
  try {
    const response = await axios.get(`https://restcountries.eu/rest/v2/currency/${currencyCode}`);
    
return response.data.map(country => country.name);
  } catch (error) {
    throw new Error(`Unable to get countries that use ${currencyCode}`);
  }
};

And since the third function is just working with what the first and the second function provided, there is no need for error checking there.

Finally, we can call the function and receive the data:

convertCurrency('USD', 'HRK', 20)
  .then((message) => {
    console.log(message);
  }).catch((error) => {
    console.log(error.message);
  });

The output you’re going to receive:

That’s it!

You made it all the way until the end! If you get stuck along the way, feel free to check out the code on this repository. If you have any questions or feedback, let me know in the comments down below. Most helpful would be the support on YouTube since I have just created a channel! Click here, there is a lot of interesting stuff coming soon! :)