Перед вами перевод статьи Adrian Hajdin, которая была опубликована на сайте freeCodeCamp. Под катом автор понятно и лаконично объясняет, в чем преимущество async/await, и на конкретном примере показывает, как использовать этот синтаксис.
На заметку…
Я не только написал эту статью, но и создал видео на YouTube!
Вы можете следовать инструкциям в ролике и программировать в процессе просмотра. Я советую сначала прочесть статью и уже потом писать код по ходу видео.
Ссылка на видео: Learn Async/Await in This Real World Project
Async/await — это новый способ написания асинхронного кода. Этот синтаксис построен поверх промисов и поэтому не является блокирующим.
Отличие от других способов создания асинхронного кода в том, что по виду и поведению асинхронный код, который реализован через async/await, напоминает синхронный. И в этом его преимущество.
Предыдущими способами организации асинхронного кода были функции обратного вызова (callbacks) и промисы (promises).
При вложении функций обратного вызова друг в друга код вскоре начинает выглядеть вот так:
«Ад обратных вызовов» (Callback Hell)
Ад обратных вызовов
Это ситуация, при которой обратные вызовы вкладываются в другие обратные вызовы в несколько уровней, из-за чего бывает трудно понимать код и управлять им.
promiseFunction возвращает промис, который представляет процесс этой функции. Функция resolve дает объекту Promise понять, что процесс завершен.
Затем мы можем вызвать .then() и .catch() для этой функции промиса:
then — запускает обратный вызов, который вы передаете, когда промис завершен.
catch — запускает обратный вызов, который вы передаете, когда что-то пошло не так.
Функции async предоставляют нам чистый и лаконичный синтаксис, который позволяет писать меньше кода и получать такой же результат, как и при использовании промисов. Async — это не что иное, как синтаксический сахар для промисов.
Функции async создаются путем добавления ключевого слова async перед объявлением функции, например:
Выполнение асинхронных функций можно приостановить с помощью await — ключевого слова, которое используется только внутри функции async. Await возвращает все, что возвращает функция async при ее выполнении.
Различие между промисами и async/await:
Async/await похож на синхронный код, который гораздо легче понять.
Теперь, когда мы осветили основные принципы, давайте перейдем к реальному примеру использования!
Сейчас мы построим простое, но полезное (в том числе для обучения) приложение, которое улучшит ваши общие знания async/await.
Программа возьмет сумму денег, код валюты, из которой мы хотим перевести эту сумму, и код валюты, в которую мы хотим ее перевести. Затем программа выдаст верный курс обмена, основанный на данных из API.
В этом приложении мы собираемся получить данные из двух асинхронных источников:
Прежде всего создайте новую папку и запустите
Сначала запросите axios, введя:
Наша цель — чтобы у программы было три функции. Не одна и не две, а именно три асинхронные функции. Первая функция будет получать данные о валютах, вторая — о странах, а третья — собирать эту информацию в одном месте и выводить ее пользователю в упорядоченном виде.
Первая функция — асинхронное получение данных о валютах
Мы создадим асинхронную функцию, которая будет включать два аргумента — fromCurrency и toCurrency.
Теперь нужно получить данные. Используя async/await, можно назначить данные напрямую переменной. Не забудьте зарегистрироваться и ввести свой ключ доступа.
Данные от ответа доступны в
Поскольку все конвертируется из евро, ниже мы создадим переменную под названием euro, которая будет равна 1/валюты, из которой мы хотим перевести деньги:
И чтобы получить обменный курс, нужно умножить евро на валюту, в которую мы хотим перевести деньги:
В результате функция должна выглядеть примерно вот так:
Вторая функция — асинхронное получение данных о стране
Мы создадим асинхронную функцию, которая будет использовать в качестве аргумента currencyCode:
Как и в прошлый раз, мы собираемся получить данные и назначить их переменной:
Затем мы установим соответствие в данных и вернем
В результате функция должна выглядеть примерно вот так:
Третья и последняя функция — объединяем все вместе
Мы создадим асинхронную функцию, которая будет включать fromCurrency, toCurrency и сумму в качестве аргументов:
Сначала получим данные о валюте:
Затем данные о странах:
После этого сохраним конвертированную сумму в переменную:
В итоге мы выводим все это пользователю:
Все вместе это должно выглядеть вот так:
Добавление оператора try/catch для обработки ошибок
Нам нужно обернуть нашу логику блоком try/catch, чтобы отловить ошибки, если они есть:
Проделайте то же самое со второй функцией:
Нет необходимости проверять на наличие ошибок третью функцию, поскольку она работает с данными, которые ей предоставляют первая и вторая функции.
В результате мы можем вызвать функцию и получить данные:
Результат, который вы получите:
Вы проделали весь путь до конца! Если у вас что-то не получилось в процессе, вы можете найти исходный код в этом репозитории. Если у вас есть вопросы или вы хотите оставить отзыв, напишите комментарий. Для меня самой большой помощью была бы ваша поддержка на YouTube, потому что я совсем недавно создал там канал! Кликайте сюда — скоро здесь появится много чего интересного! :)
Вы также можете посмотреть туториал, который я создал на сайте Mongoose.
На заметку…
Я не только написал эту статью, но и создал видео на YouTube!
Вы можете следовать инструкциям в ролике и программировать в процессе просмотра. Я советую сначала прочесть статью и уже потом писать код по ходу видео.
Ссылка на видео: Learn Async/Await in This Real World Project
Введение
Async/await — это новый способ написания асинхронного кода. Этот синтаксис построен поверх промисов и поэтому не является блокирующим.
Отличие от других способов создания асинхронного кода в том, что по виду и поведению асинхронный код, который реализован через async/await, напоминает синхронный. И в этом его преимущество.
Предыдущими способами организации асинхронного кода были функции обратного вызова (callbacks) и промисы (promises).
Функции обратного вызова в действии
setTimeout(() => {
console.log('This runs after 1000 milliseconds.');
}, 1000);
Проблема функций обратного вызова — пресловутый «ад обратных вызовов» (Callback Hell)
При вложении функций обратного вызова друг в друга код вскоре начинает выглядеть вот так:
«Ад обратных вызовов» (Callback Hell)
Ад обратных вызовов
Это ситуация, при которой обратные вызовы вкладываются в другие обратные вызовы в несколько уровней, из-за чего бывает трудно понимать код и управлять им.
Промисы в действии
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 дает объекту Promise понять, что процесс завершен.
Затем мы можем вызвать .then() и .catch() для этой функции промиса:
then — запускает обратный вызов, который вы передаете, когда промис завершен.
catch — запускает обратный вызов, который вы передаете, когда что-то пошло не так.
Функции async
Функции async предоставляют нам чистый и лаконичный синтаксис, который позволяет писать меньше кода и получать такой же результат, как и при использовании промисов. Async — это не что иное, как синтаксический сахар для промисов.
Функции async создаются путем добавления ключевого слова async перед объявлением функции, например:
const asyncFunction = async () => {
// Code
}
Выполнение асинхронных функций можно приостановить с помощью await — ключевого слова, которое используется только внутри функции async. Await возвращает все, что возвращает функция async при ее выполнении.
Различие между промисами и 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 — https://currencylayer.com — вам нужно будет бесплатно зарегистрироваться, чтобы воспользоваться ключом доступа 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, можно назначить данные напрямую переменной. Не забудьте зарегистрироваться и ввести свой ключ доступа.
const getExchangeRate = async (fromCurrency, toCurrency) => {
const response = await axios.get('http://data.fixer.io/api/latest? access_key=[yourAccessKey]&format=1');
}
Данные от ответа доступны в
response.data.rates
, поэтому можно вставить это выражение в переменную прямо под response: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/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);
});
Результат, который вы получите:
Вот и все!
Вы проделали весь путь до конца! Если у вас что-то не получилось в процессе, вы можете найти исходный код в этом репозитории. Если у вас есть вопросы или вы хотите оставить отзыв, напишите комментарий. Для меня самой большой помощью была бы ваша поддержка на YouTube, потому что я совсем недавно создал там канал! Кликайте сюда — скоро здесь появится много чего интересного! :)
Вы также можете посмотреть туториал, который я создал на сайте Mongoose.
Комментарии (2)
donRumatta
31.01.2019 23:08Было, но перевод здесь кажется более литературным. Оформление зато у RUVDS приятнее глазу(=
akdes
Как бы уже было…
тыц