Как освоить Async / Await в JavaScript на реальных примерах

Как освоить Async / Await в JavaScript на реальных примерах

От автора: Async / await — это новый способ написания асинхронного кода. Он построен на основе promises, поэтому он также является не блокирующим. Разница заключается в том, что асинхронный код выглядит и ведет себя немного больше как синхронный. Вот в чем вся его сила.

Наряду с написанием этой статьи я также создал видео на YouTube! Вы можете смотреть его и кодировать во время просмотра. Советую сначала прочитать статью, а затем написать код, руководствуясь видео.Ссылка на видео: Изучаем Async / Await на реальном проекте.

Предыдущими вариантами асинхронного кода были обратные вызовы и promises.

Обратные вызовы в действии

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

Проблема с обратными вызовами  -  печально известный ад обратных вызовов

Вложенные обратные вызовы внутри обратных вызовов скоро начнут выглядеть так:

Ад обратных вызовов

Ситуация, когда обратные вызовы вложены в другие обратные вызовы на несколько уровней, что потенциально затрудняет понимание и поддержку кода.

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

promiseFunction возвращает Promise, который представляет процесс этой функции. Функция разрешения сообщает об окончании экземпляра Promise. После этого мы можем вызвать для этой функции .then() и .catch():

then — запускает обратный вызов, который вы передали ему для случая, когда Promise выполнен.

catch  - запускает обратный вызов, который вы передали ему для случая, когда что-то пошло не так.

Асинхронные функции

Асинхронная функция предоставляет нам чистый и лаконичный синтаксис, позволяющий писать меньше кода для достижения того же результата, который мы получили бы с помощью Promise. Async — не более чем синтаксический сахар для Promise. Асинхронные функции создаются путем добавления слова async перед объявлением функции следующим образом:

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

Асинхронные функции могут быть приостановлены с помощью await, ключевого слова, которое может быть использовано только внутри асинхронной функции. Await возвращает все, что возвращает асинхронная функция, когда она завершена. В этом разница между promises и 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 выглядят аналогично синхронному коду, а синхронный код гораздо легче понять. Теперь, когда мы рассмотрели основы, давайте перейдем к примеру из реального мира!

Конвертер валют

Разъяснение и настройка проекта

В этом руководстве мы создадим простое, но полезное приложение, которое улучшит ваши общие знания об Async / Await.

Программа будет принимать код валюты, из которой мы хотим конвертировать, и код валюты, в которую мы хотим конвертировать, а также сумму. После этого программа выведет корректный обменный курс на основе данных из API.

В этом приложении мы собираемся получать данные из двух асинхронных источников:

Currency Layer - вам нужно бесплатно зарегистрироваться, чтобы использовать ключ доступа API. Этот API предоставит нам данные, необходимые для расчета обменного курса между валютами.

Rest Countries - этот 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 мы можем назначать данные непосредственно переменной; не забудьте зарегистрироваться и ввести свой корректный ключ доступа.

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;

Поскольку все конвертируется из евро, ниже мы создадим переменную с именем 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);

В конце функция должна выглядеть примерно так:

Третья и последняя функция — объединение всего вместе

Мы создадим асинхронную функцию, которая будет принимать в качестве аргументов 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}`;

Все это вместе должно выглядеть так:

Добавление try / catch для устранения ошибок

Нам нужно обернуть всю нашу логику в try и перехватить ошибку, если она есть:

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

Результат:

Вот и все!

Мы закончили! Если вы что-то не уловили, код доступен в этом хранилище.

Автор: Adrian Hajdin

Источник: https://medium.freecodecamp.org/

Редакция: Команда webformyself.