JavaScript

Как освоить Async/Await с примером из реальной жизни

Spread the love

Оглавление:

  1. Введение (callbacks, promises, async/await)
  2. Пример из реальной жизни —  Конвертер валют, который получает асинхронные данные от двух 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.

  1. Currency Layer https://currencylayer.com —  Для использования ключа доступа API нужно пройти бесплатную зарегистрацию. Этот API предоставит нам все необходимые данные для расчета обменного курса между валютами.
  2. Rest Countrieshttp://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);
  });

Завершение

Это все что я хотел рассказать а асинхронных функциях. Если вы у вас возникли сложности в запуском примера, не стесняйтесь проверить код в этой статье. Если у вас есть какие-либо вопросы или пожелания, дайте мне знать в комментариях ниже.

Оригинал

Была ли вам полезна эта статья?
[5 / 4.6]

Spread the love
Editorial Team

Recent Posts

Vue 3.4 Новая механика v-model компонента

Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование​ v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…

11 месяцев ago

Анонс Vue 3.4

Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…

11 месяцев ago

Как принудительно пере-отобразить (re-render) компонент Vue

Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…

2 года ago

Проблемы с установкой сертификата на nginix

Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…

2 года ago

Введение в JavaScript Temporal API

Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…

2 года ago

Когда и как выбирать между медиа запросами и контейнерными запросами

Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…

2 года ago