Понимаем Async/Await на примере Конвертера Валют

Содержание:
- Вступление (колбэки, промисы, async/await)
- Реальный пример— Конвертер Валют, обрабатывающий асинхронные данные из двух API.
На заметку…
Вместе со статьей, автор записал и YouTube видео [ENG]!
Вступление
Async/await - это новый способ написания асинхронного кода в JS. Он построен поверх промисов, поэтому не блокирует параллельные операции.
Ранее вариантами написания асинхронного кода были: колбэки и промисы.
Колбэки в действии
setTimeout(() => {
console.log('Это сообщение отобразится через 1000 миллисекунд.');
}, 1000);
Проблемы колбэков — Ад колбэков
Вкладывая колбэки внутри колбэков в скором времени мы получим что-то подобное:

Ад колбэков
Ситуация, в которой колбэки вкладываются внутрь других колбэков на несколько уровней вглубь, в перспективе делает код сложным к пониманию и трудно поддерживаемым.
Промисы в действии
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 возвращает Промис, который представляет процесс этой функции. Функция resolve оповещает сущность Промиса о завершении работы.
Впоследствии, мы можем вызвать .then() и .catch() относительно функции промиса:
then — Запускает колбэк, который вы ей(then) передаете, когда промис закончит работу.
catch — Runs a callback you pass to it when something went wrong.
Асинхронные функции
Асинхронная функция предоставляет нам чистый и лаконичный синтаксис для написания меньшего количества кода, добиваясь того же результата, что и с промисами. Async является синтаксическим сахаром для промисов.
Чтобы создать асинхронную функцию нужно добавить слово async перед объявлением функции:
const asyncFunction = async () => {
// Код
}
Работу асинхронных функций можно приостановить с помощью await, ключевое слово используемое только внутри асинхронных функций. Await вернет значение возвращаемое асинхронной функцией после окончания её работы.
Отличие между промисами и async/await:
// Async/Await
const asyncGreeting = async () => 'Привет';// Промис
const promiseGreeting = () => new Promise(((resolve) => {
resolve('Привет');
}));
asyncGreeting().then(result => console.log(result));
promiseGreeting().then(result => console.log(result));
Конструкция Async/Await похожа на синхронный код, который куда легче для восприятия.
Итак, мы прошли основы, пора погрузиться в пример из реального мира!
Конвертер Валют
В этом руководстве мы создадим простое, но полезное приложение, которое поможет нам разобраться в Async/Await.
Приложение принимает три аргумента: код валюты, которую пользователь хочет ковертировать и код валюты, в которую пользователь хочет конвертировать, также колличество денежных единиц. После чего приложение выведет результат конвертации базируясь на данных из API.
В этом приложении мы будем запрашивать данные из двух асинхронных ресурсов:
- Currency Layer — https://currencylayer.com — Вам нужно зарегистрироваться, чтобы использовать ключ доступа к API. API предоставит нам данные для вычисления курса обмена между валютами.
- Rest Countries — http://restcountries.eu/ — API предоставит нам информацию о том, в каких странах используется конвертируемая нами валюта.
Для начала создайте новую папку и запустите команду npm init
, можете смело пропускать все шаги through all the steps. Установите axios выполнив npm i --save axios.
Создайте новый файл currency-converter.js.
Первым делом объявите axios в начале файла:const axios = require(‘axios’);
Погружаемся в async/await
Определим цель: создать три функции. Не одну, не две, а три асинхронных функции. Первая будет запрашивать данные о валютах. Вторая функция запросит данные о странах. Третья обработает эту информацию и выдаст ее в привычном для пользователя виде.
Первая функция —Асинхронное получение данных о Валюте
Мы создадим асинхронную функцию, которая принимает два аргумента: fromCurrency and toCurrency.
fromCurrency — код конвертируемой валюты.
toCurrency — код валюты в которую конвертируем.
const getExchangeRate = async (fromCurrency, toCurrency) => {}
Теперь нам предстоит запросить данные. С помощью async/await, мы можем определить данные сразу в переменную; не забудьте зарегистрироваться и ввести свой ключ доступа.
const getExchangeRate = async (fromCurrency, toCurrency) => {
const response = await axios.get('http://data.fixer.io/api/latest? access_key=[ВАШ_КЛЮЧ_ДОСТУПА]&format=1');
}
Данные из ответа (response) доступны по следующему пути:response.data.rates
. Определим их в переменную под ответом:
const rate = response.data.rates;
Так как мы конвертируем в Евро, ниже, создадим переменную под названием euro и зададим ей значение — 1/валюта, которую мы конвертируем:
const euro = 1 / rate[fromCurrency];
Наконец, чтобы получить курс обмена нам нужно умножить евро в валюту которую мы хотим конвертировать:
const exchangeRate = euro * rate[toCurrency];
Функция должна выглядеть примерно так:

Вторая функция— Асинхронное получение данных о стране
Создадим асинхронную функцию, которая принимает аргумент currencyCode(код валюты):
const getCountries = async (currencyCode) => {}
Как и раньше, мы запрашиваем данные и определяем их в переменную:
const response = await axios.get(
`https://restcountries.eu/rest/v2/currency/${currencyCode}`
);
Перебираем массив данных и возвращаем country.name
для каждого элемента:
return response.data.map(country => country.name);
Конечный вариант функции:

Третья и последняя функция — Соединяем данные вместе
Создадим асинхронную функцию принимающую 3 аргумента: fromCurrency, toCurrency, amount.
const convert = async (fromCurrency, toCurrency, amount) => {}
Запрашиваем данные о Валютах:
const exchangeRate = await getExchangeRate(
fromCurrency,
toCurrency
);
Запрашиваем данные о странах:
const countries = await getCountries(toCurrency);
Сохраняем конвертированные данные в переменную:
const convertedAmount = (amount * exchangeRate).toFixed(2);
Выводим результат для пользователя:
return `${amount} ${fromCurrency} стоит ${convertedAmount} ${toCurrency}. Вы можете потратить валюту в приведённых странах странах: ${countries}`;
Вы должны получить что-то подобное:

Добавляем try/catch для отлова ошибок
Нам нужно обернуть логику приложения в try, и “поймать”(catch) ошибку, если такова будет:
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(`Не выходит получить курс обмена для ${fromCurrency} и ${toCurrency}`);
}
};
Повторим тоже самое для второй функции:
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(`Не выходит получить страны использующие ${currencyCode}`);
}
};
Так как третья функция использует данные передаваемые первой и второй функцией — нет нужды проверять на ошибки третью функцию.
Наконец, мы можем вызвать функцию и получить данные:
convertCurrency('USD', 'HRK', 20)
.then((message) => {
console.log(message);
}).catch((error) => {
console.log(error.message);
});
Вы получите примерно такой ответ:

Оригинал статьи — ссылка
