A construção assíncrona / espera é uma abordagem relativamente nova para escrever código assíncrono em JavaScript. É baseado em promessas e, como resultado, não bloqueia o fluxo principal. A inovação desse design é que, graças a ele, o código assíncrono se torna semelhante ao síncrono e se comporta de maneira semelhante. Isso abre grandes oportunidades para o programador.

Antes do advento do assíncrono / espera, retornos de chamada e promessas eram usadas no desenvolvimento de mecanismos de programas assíncronos. O autor do material, cuja tradução estamos publicando hoje, sugere primeiro relembrar como escrever código da maneira antiga e, em seguida, usando um exemplo real, estudar o uso de async / wait.
Retornos de chamada
Aqui está um código de exemplo que usa retornos de chamada (funções de retorno de chamada):
setTimeout(() => { console.log('This runs after 1000 milliseconds.'); }, 1000);
Ao usar as funções de retorno de chamada aninhadas, há um problema chamado inferno de retorno de chamada. Aqui está um exemplo de código simplificado para ilustrar esse problema:
asyncCallOne(() => { asyncCallTwo(() => { asyncCallThree(() => { asyncCallFour(() => { asyncCallFive(() => {
Se o código contiver estruturas que consistem em retornos de chamada aninhados um no outro, esse código pode ser difícil de entender, será difícil de manter.
Promessas
Aqui está um código de exemplo que usa promessas (objetos Promise):
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); });
A função
promiseFunction()
deste exemplo retorna um objeto
Promise
, que é uma determinada ação executada pela função. Uma chamada para o método
resolve()
indica a promessa de que sua operação foi concluída com êxito. Nessas construções, o método
.then()
de promessas também é usado - com sua ajuda, após a resolução bem-sucedida da promessa, você pode executar um determinado retorno de chamada. O método
.catch()
é chamado se algo der errado durante o trabalho da promessa.
Funções assíncronas
As funções declaradas usando a
async
(funções assíncronas) nos dão a oportunidade de escrever um código limpo e não sobrecarregado com construções de serviço, o que nos permite obter o mesmo resultado que obtivemos usando promessas. Note-se que a
async
é essencialmente apenas "açúcar sintático" para promessas.
Funções assíncronas são criadas usando a palavra
async
chave
async
ao declarar uma função. É assim:
const asyncFunction = async () => {
Funções assíncronas podem ser pausadas usando a palavra-chave
await
. Só pode ser usado em funções assíncronas. Ele permite que você retorne o resultado da função assíncrona, que estará disponível após essa função concluir a execução de uma tarefa.
Compare a operação de uma função assíncrona e uma promessa que retorna uma string:
É fácil ver que o uso da
async
permite que você escreva um código assíncrono que pareça síncrono. Esse código é muito mais fácil de trabalhar.
Agora que cobrimos as coisas básicas, passemos ao nosso exemplo.
Conversor de moeda
Preparation Preparação preliminar
Aqui, criaremos um simples, mas cognitivo, do ponto de vista do estudo da construção da aplicação assíncrona / aguardada. É um conversor de moeda que usa dados reais obtidos das APIs correspondentes. O programa aceita o valor em uma determinada moeda, o código dessa moeda, bem como o código da moeda no qual queremos converter esse valor. Depois disso, o programa exibe o resultado baixando primeiro os dados atuais sobre as taxas de câmbio. O programa também exibe uma lista de países nos quais você pode gastar dinheiro na moeda para a qual a quantia especificada é transferida.
Em particular, aqui vamos usar dados de duas fontes de informação assíncronas:
- Serviço Currencylayer.com . Neste site, você precisará criar uma conta gratuita e obter uma chave para acessar a API (API Access Key). A partir daqui, coletaremos os dados necessários para a conversão do valor de uma moeda para outra.
- Serviço restcountries.eu . Pode ser usado sem registro. A partir daqui, enviamos dados sobre onde você pode usar a moeda na qual convertemos a quantia especificada.
Crie um novo diretório e execute o comando
npm init
nele. Quando o programa nos fizer uma pergunta sobre o nome do pacote que está sendo criado, apresentaremos o
currency-converter
. Você não pode responder a outras perguntas do programa pressionando
Enter
em resposta. Depois disso, instale o pacote Axios em nosso projeto executando o
npm install axios --save
em seu diretório Crie um novo arquivo chamado
currency-converter.js
.
Vamos começar a escrever o código do programa conectando o Axios neste arquivo:
const axios = require('axios');
Nosso projeto terá três funções assíncronas. O primeiro carregará os dados da moeda. O segundo carregará os dados do país. O terceiro coletará esses dados, os apresentará de forma amigável e os exibirá na tela.
▍ A primeira função é o carregamento assíncrono de dados da moeda
Vamos criar uma função assíncrona
getExchangeRate()
que receberá dois argumentos:
fromCurrency
e
toCurrency
:
const getExchangeRate = async (fromCurrency, toCurrency) => {}
Nesta função, precisamos carregar dados. Usando a construção assíncrona / espera, você pode gravar os dados recebidos diretamente em uma determinada variável ou constante. Antes de escrever o código para esta função, não se esqueça de se registrar
no site e obter uma chave de acesso à API. Para carregar dados, precisamos da seguinte construção:
const response = await axios.get('http://www.apilayer.net/api/live?access_key=[ API]');
Após receber a resposta do sistema, os dados de que precisamos podem ser encontrados no objeto de
response.data.quotes
em
response.data.quotes
. Aqui está o fragmento do objeto com os dados de interesse para nós (é visível no programa como
response.data
):
{ "success":true, "terms":"https:\/\/currencylayer.com\/terms", "privacy":"https:\/\/currencylayer.com\/privacy", "timestamp":1547891348, "source":"USD", "quotes":{ "USDAED":3.673042, "USDAFN":75.350404, "USDALL":109.203989, ... "USDZWL":322.355011 } }
Coloque o objeto com taxas de câmbio na
rate
constante:
const rate = response.data.quotes;
O código da moeda base pode ser encontrado em
response.data.source
. Escrevemos o código da moeda base na constante
baseCurrency
:
const baseCurrency = response.data.source;
Como, por padrão, os dados retornados por esta API são a taxa de câmbio em relação ao dólar americano (USD), crie um
usd
constante no qual escreveremos o resultado da divisão 1 pela taxa de câmbio na qual o valor é especificado:
const usd = 1 / rate[`${baseCurrency}${fromCurrency}`];
Preste atenção em como a chave é formada, de acordo com a qual obtemos o valor do curso. No objeto obtido da API, cujo fragmento é mencionado acima, as chaves são cadeias que começam com
USD
e terminam com o código da moeda correspondente. Como se supõe que nosso programa aceite códigos de moeda da string, geramos uma chave concatenando uma string contendo o código da moeda base e o que é passado para a função no parâmetro
fromCurrency
.
Agora, para obter a taxa de câmbio de
fromCurrency
para
toCurrence
, multiplicamos o
usd
constante pela taxa de
toCurrency
. É assim:
const exchangeRate = usd * rate[`${baseCurrency}${toCurrency}`];
Como resultado, retornaremos o que entra em
exchangeRate
. Aqui está a aparência do seu código completo:
const getExchangeRate = async (fromCurrency, toCurrency) => { try { const response = await axios.get('http://www.apilayer.net/api/live?access_key=[ API]'); const rate = response.data.quotes; const baseCurrency = response.data.source; const usd = 1 / rate[`${baseCurrency}${fromCurrency}`]; const exchangeRate = usd * rate[`${baseCurrency}${toCurrency}`]; return exchangeRate; } catch (error) { throw new Error(`Unable to get currency ${fromCurrency} and ${toCurrency}`); } };
Observe que a construção try / catch regular é usada para manipular erros que podem ocorrer durante a execução da consulta.
Second A segunda função é o carregamento assíncrono dos dados do país
Nossa segunda função,
getCountries()
, que carrega assincronamente informações sobre países nos quais você pode usar a moeda na qual converteremos o valor especificado em outra moeda, aceitará o argumento
currencyCode
:
const getCountries = async (currencyCode) => {}
Para carregar dados, usamos o seguinte comando:
const response = await axios.get(`https://restcountries.eu/rest/v2/currency/${currencyCode}`);
Se, por exemplo, usarmos o código
HRK
(croata kuna) na solicitação, receberemos um código JSON em resposta, cujo fragmento é mostrado abaixo:
[ { "name":"Croatia", ... } ]
É uma variedade de objetos com informações sobre países. As propriedades do
name
desses objetos contêm o nome do país. Você pode acessar essa matriz usando a construção
response.data
. Aplicamos o método de matriz
map()
para extrair os nomes dos países dos dados recebidos e retornar esses dados da função
getCountries()
, que será uma matriz de nomes de países:
return response.data.map(country => country.name);
Aqui está o código completo da função
getCountries()
:
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}`); } };
Ird Terceira função - coleta e saída de dados
Nossa terceira função assíncrona,
convertCurrency ()
, aceitará os argumentos de
fromCurrency
,
toCurrency
e
amount
- códigos e quantia de moeda.
const convertCurrency = async (fromCurrency, toCurrency, amount) => {}
Nele, obtemos primeiro a taxa de câmbio:
const exchangeRate = await getExchangeRate(fromCurrency, toCurrency);
Em seguida, carregamos a lista de países:
const countries = await getCountries(toCurrency);
Em seguida, realizamos a conversão:
const convertedAmount = (amount * exchangeRate).toFixed(2);
E depois que todos os dados necessários são coletados, retornamos a linha que o usuário do programa verá:
return `${amount} ${fromCurrency} is worth ${convertedAmount} ${toCurrency}. You can spend these in the following countries: ${countries}`;
Aqui está o código completo da função:
const convertCurrency = 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}`; };
Observe que esta função não possui um bloco try / catch, pois só funciona com os resultados fornecidos pelas duas funções descritas anteriormente.
▍Inicie o programa
Preparamos três funções, duas das quais carregam dados de vários serviços, e uma coleta esses dados e prepara a saída. Agora só precisamos chamar essa função, passando tudo o que precisamos. Não implementaremos mecanismos aqui que permitam chamar nosso programa a partir da linha de comando com a transferência de códigos de moeda e soma para ele, embora você possa fazer isso se desejar. Apenas chamamos a função
convertCurrency()
, passando os dados necessários:
convertCurrency('EUR', 'HRK', 20) .then((message) => { console.log(message); }).catch((error) => { console.log(error.message); });
Aqui, queremos descobrir quanto kuna croata pode ser trocado por 20 euros e, ao longo do caminho, descobrir em quais países esse dinheiro pode ser gasto.
Chamamos o programa digitando o seguinte comando no terminal:
node currency-converter.js
Em resposta, abordamos o seguinte.
O resultado do programaAqui, por precaução, o código completo do nosso projeto.
const axios = require('axios'); const getExchangeRate = async (fromCurrency, toCurrency) => { try { const response = await axios.get('http://www.apilayer.net/api/live?access_key=[ API]'); const rate = response.data.quotes; const baseCurrency = response.data.source; const usd = 1 / rate[`${baseCurrency}${fromCurrency}`]; const exchangeRate = usd * rate[`${baseCurrency}${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}`); } }; const convertCurrency = 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}`; }; convertCurrency('EUR', 'HRK', 20) .then((message) => { console.log(message); }).catch((error) => { console.log(error.message); });
Sumário
Esperamos que este exemplo de uso da construção assíncrona / espera em condições reais ajude aqueles que não entenderam essa construção antes a descobrir isso.
Caros leitores! Se você usar a construção assíncrona / aguardada na prática, compartilhe suas impressões sobre ela.