📜 ⬆️ ⬇️

How to master the syntax async / await: a real example

This is a translation of the article by Adrian Hajdin, which was published on the freeCodeCamp website. Under the author, the author clearly and concisely explains the advantages of async / await, and shows how to use this syntax using a specific example.



On a note…

I not only wrote this article, but also created a video on YouTube!

You can follow the instructions in the video and program in the process of viewing. I advise you first to read the article and then write the code in the course of the video.

Video link: Learn Async / Await in This Real World Project

Introduction


Async / await is a new way to write asynchronous code. This syntax is built on top of promises and therefore is not blocking.

The difference from other ways of creating asynchronous code is that in appearance and behavior, asynchronous code that is implemented via async / await resembles synchronous. And this is his advantage.

Previous ways to organize asynchronous code were callbacks and promises.

Callback functions in action


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

Callback functions problem - the notorious “callback hell”


When nesting callbacks into each other, the code soon begins to look like this:


Callback Hell

Hell callbacks

This is a situation in which callbacks are embedded in other callbacks at several levels, which makes it difficult to understand and manage 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 this function. The resolve function makes the Promise object understand that the process is complete.

Then we can call .then () and .catch () for this promise function:
then - launches the callback that you transmit when the promise is complete.
catch - triggers a callback that you send when something goes wrong.

Async functions


The async functions provide us with a clean and concise syntax that allows us to write less code and get the same result as when using promises. Async is nothing but syntactic sugar for promis.

Async functions are created by adding the async keyword before declaring a function, for example:

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

Asynchronous functions can be suspended using await , a keyword that is used only inside the async function . Await returns everything that the async function returns when it is executed.

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 is similar to synchronous code, which is much easier to understand.

Now that we have covered the basic principles, let's move on to a real use case!

Currency Converter


Clarification and customization of the project


Now we will build a simple, but useful (including for training) application that will improve your general knowledge of async / await .

The program will take the amount of money, the currency code from which we want to transfer this amount, and the currency code into which we want to transfer it. The program will then issue the correct exchange rate based on data from the API.

In this application, we are going to get data from two asynchronous sources:

  1. Currency Layer - https://currencylayer.com - you will need to register for free to use the API access key. He will provide us with the data necessary to calculate the exchange rate.
  2. Rest Countries - http://restcountries.eu/ - this API will provide information on where we can use the currency into which we just transferred our money.

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

First, query axios by typing: const axios = require('axios');

Let's dive into async / await


Our goal is for the program to have three functions. Not one and not two, namely three asynchronous functions . The first function will receive data on currencies, the second - about countries, and the third - to collect this information in one place and display it to the user in an orderly manner.

The first function is asynchronous receipt of currency data.

We will create an asynchronous function that will include two arguments - fromCurrency and toCurrency.

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

Now you need to get the data. Using async / await, you can assign data directly to a variable. Do not forget to register and enter your access key.

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

Data from the response is available in response.data.rates , so you can insert this expression into the variable directly under the response:

 const rate = response.data.rates; 

Since everything is converted from euro, below we will create a variable called euro, which will be equal to 1 / of the currency from which we want to transfer money:

 const euro = 1 / rate[fromCurrency]; 

And to get the exchange rate, you need to multiply the euro by the currency in which we want to transfer money:

 const exchangeRate = euro * rate[toCurrency]; 

As a result, the function should look something like this:



The second function is asynchronous acquisition of country data.

We will create an asynchronous function that will use the currencyCode argument:

 const getCountries = async (currencyCode) => {} 

Like last time, we are going to get the data and assign it to a variable:

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

Then we establish a match in the data and return country.name for each currency code:

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

As a result, the function should look something like this:



The third and last function - combine them all together.
We will create an asynchronous function that will include fromCurrency , toCurrency, and an amount as arguments:

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

First we get the currency information:

 const exchangeRate = await getExchangeRate(fromCurrency, toCurrency); 

Then the country data:

 const countries = await getCountries(toCurrency); 

After that, save the converted amount to a variable:

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

As a result, we output all this to the user:

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

Collectively, it should look like this:



Adding a try / catch statement to handle errors
We need to wrap our logic with a try / catch block to catch errors, if any:

 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}`); } }; 

Do the same with 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}`); } }; 

There is no need to check for a third function for errors, since it works with the data that the first and second functions provide to it.

As a result, we can call the function and get the data:

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

The result you get:



That's all!


You have come all the way to the end! If something went wrong in the process, you can find the source code in this repository . If you have questions or want to leave a review, write a comment . For me, your support on YouTube would be the biggest help, because I recently created a channel there! Click here - soon there will be a lot of interesting things! :)

You can also watch the tutorial that I created on the Mongoose website.

Source: https://habr.com/ru/post/438318/