Как освоить Async/Await с примером из реальной жизни
Оглавление:
- Введение (callbacks, promises, async/await)
- Пример из реальной жизни — Конвертер валют, который получает асинхронные данные от двух API.
Введение
Использование async/await — это еще один способ написания асинхронного кода. Он так же построен на основе обещаний (promises). Основное отличие от promises в том, что асинхронный код выглядит и ведет себя так же как синхронный код. Но в этом и есть основное преимущество этого способа.
Предыдущие варианты асинхронного кода callbacks и promises.
Обратные вызовы (Callbacks) в действие
setTimeout(() => { console.log('This runs after 1000 milliseconds.'); }, 1000);
Проблемы с обратными вызовами — Печально известный как ад обратных вызовов
Вложенные обратные вызовы внутри обратных вызовов очень быстро могут начать выглядеть так:
asyncCallOn(() => { asyncCallOn(() => { asyncCallOn(() => { asyncCallOn(() => { asyncCallOn(() => { asyncCallOn(() => { asyncCallOn(() => { // Какие либо действия }) }) }) }) }) }) })
Callback Hell
Ситуация, когда обратные вызовы вложены в другие обратные вызовы на несколько уровней, потенциально затрудняет понимание и поддержку кода.
Promises в действие
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); });
Функция promise возвращает Promise которая содержит внутри себя процесс обработки которое должно быть запущено в случае успеха и неуспеха окончания обработки функции.
После этого, можно вызвать .then() и .catch() для функции promise:
then — Запускает обратный вызов (callback), который вы передаете ему, когда обещание (promise) завершено.
catch — Запускает обратный вызов (callback), который вы передаете ему, когда что-то пошло не так.
Async функции
Async функция предоставляет чистый и лаконичный синтаксис, который позволяет писать меньше кода для достижения того же результата, который мы получили бы с обещаниями. Async — не более чем синтаксический сахар для обещаний (promises).
Async функции создаются путем добавления слова async перед объявлением функции следующим образом:
const asyncFunction = async () => { // Code }
Оператор await
заставляет функцию, объявленную с использованием оператора async
, ждать выполнения Promise
и продолжать выполнение после возвращения Promise
значения. Впоследствии возвращает полученное из Promise
значение.
Await может быть использовано только внутри async функций.
// Async/Await function resolveAfter2Seconds(x) { return new Promise(resolve => { setTimeout(() => { resolve(x); }, 2000); }); } async function f1() { var x = await resolveAfter2Seconds(10); console.log(x); // 10 } f1();
Async/Await позволяет использовать асинхронный код, который выглядит как синхронный код, что намного удобнее для понимания кода программ.
Теперь, когда мы рассмотрели основы, давайте перейдем к нашему примеру из реального мира!
Конвертер валют
Разъяснение и настройка проекта
В этом руководстве мы создадим простое, но полезное приложение, которое позволит вам улучшит ваше понимание Async/Await.
Программа будет принимать код валюты, из которой мы хотим конвертировать, и код валюты, в которую мы хотим конвертировать, а также сумму денег. После этого программа выведет правильный обменный курс на основе данных из API.
В этом приложении мы собираемся получать данные из двух асинхронных источников:n this tutorial, we will build a simple but educational and useful application that is going to improve your overall knowledge of Async/Await.
- Currency Layer — https://currencylayer.com — Для использования ключа доступа API нужно пройти бесплатную зарегистрацию. Этот API предоставит нам все необходимые данные для расчета обменного курса между валютами.
- Rest Countries — http://restcountries.eu/ — Этот API предоставит нам информацию о том, где мы можем использовать валюту, в которую мы только что конвертировали наши деньги.
Для начало, создадим новую директорию и запустим npm init
, далее, инсталлируем axios командой npm i --save axios.
Создадим новый файл currency-converter.js.
В файле добавим загрузку axios:
const axios = require(‘axios’);
Погрузимся глубже в async/await
Наша цель для этой программы состоит в том, чтобы создать три функции. Не одна, не две, а три асинхронные функции. Первая функция будет собирать данные о валютах. Вторая функция — собирать данные о странах. И третья функция собирается собирать эту информацию в одном месте и красиво выводить ее пользователю.
Первая функция — Асинхронное получение данных валютах
Мы создадим асинхронную функцию, которая будет принимать два аргумента: fromCurrency и toCurrency.
const getExchangeRate = async (fromCurrency, toCurrency) => {}
Теперь нам нужно получить данные. С помощью async/await мы можем назначить возвращяемые асинхронной функцией данные переменной; Не забудьте зарегистрироваться на fixer.io и получить свой ключ доступа.
const getExchangeRate = async (fromCurrency, toCurrency) => { const response = await axios.get('http://data.fixer.io/api/latest? access_key=[yourAccessKey]&format=1'); }
Интересующие нас данные в ответе сервера находятся в response.data.rates
, далее нам нужно перенести их в переменную:
const rate = response.data.rates;
Поскольку все конвертируется из евро, ниже мы создадим переменную с именем евро, которая будет равна 1/валюте, из которой мы хотим конвертировать:
const euro = 1 / rate[fromCurrency];
Наконец, чтобы получить обменный курс, мы можем умножить евро на валюту, в которую мы хотим конвертировать:
const exchangeRate = euro * rate[toCurrency];
Наконец, наша функция должна выглядеть примерно так:
const getExchangeRate = async (fromCurrency, toCurrency) => { const response = await axios.get('http://data.fixer.io/api/latest? access_key=[yourAccessKey]&format=1'); const rate = response.data.rates; const euro = 1 / rate[fromCurrency]; const exchangeRate = euro * rate[toCurrency]; return exchangeRate; }
Вторая функция — Асинхронное получение данных о стране
Мы создадим асинхронную функцию, которая будет принимать в качестве аргумента 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);
Наконец, наша функция должна выглядеть примерно так:
const getCountries = async (currencyCode) => { const response = await axios.get(`https://restcountries.eu/rest/v2/currency/${currencyCode}`); return response.data.map(country => country.name); }
Третья и последняя функция — объедим все вместе
Мы создадим асинхронную функцию, которая будет принимать fromCurrency, toCurrency и сумму в качестве аргументов:
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} is worth ${convertedAmount} ${toCurrency}. You can spend these in the following countries: ${countries}`;
Все это вместе должно выглядеть так:
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} is worth ${convertedAmount} ${toCurrency}. You can spend these in the following countries: ${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(`Unable to get currency ${fromCurrency} and ${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(`Unable to get countries that use ${currencyCode}`); } };
Поскольку третья функция просто работает с тем, что возвращает первая и вторая функцией, то в ней нет необходимости проверять ошибки.
Наконец, мы можем вызвать функцию и получить данные:
convertCurrency('USD', 'HRK', 20) .then((message) => { console.log(message); }).catch((error) => { console.log(error.message); });
Завершение
Это все что я хотел рассказать а асинхронных функциях. Если вы у вас возникли сложности в запуском примера, не стесняйтесь проверить код в этой статье. Если у вас есть какие-либо вопросы или пожелания, дайте мне знать в комментариях ниже.