Dominamos async / wait en un ejemplo real

La construcción async / await es un enfoque relativamente nuevo para escribir código asincrónico en JavaScript. Se basa en promesas y, como resultado, no bloquea la transmisión principal. La innovación de este diseño es que, gracias a él, el código asíncrono se vuelve similar al síncrono y se comporta de manera similar. Esto abre grandes oportunidades para el programador.

imagen

Antes del advenimiento de async / await, se utilizaron devoluciones de llamada y promesas en el desarrollo de mecanismos de programa asincrónicos. El autor del material, cuya traducción publicamos hoy, sugiere primero recordar cómo escribir código a la antigua usanza y luego, usando un ejemplo real, estudiar el uso de async / wait.

Devoluciones de llamada


Aquí hay un código de muestra que usa devoluciones de llamada (funciones de devolución de llamada):

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

Al usar las funciones de devolución de llamada anidadas, hay un problema llamado infierno de devolución de llamada. Aquí hay un ejemplo de código simplificado para ilustrar este problema:

 asyncCallOne(() => { asyncCallTwo(() => {   asyncCallThree(() => {     asyncCallFour(() => {       asyncCallFive(() => {         //         })     })   }) }) }) 

Si el código contiene estructuras que consisten en devoluciones de llamada anidadas entre sí, dicho código puede ser difícil de entender, será difícil de mantener.

Promesas


Aquí hay un código de ejemplo que usa promesas (objetos de promesa):

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

La función promiseFunction() de este ejemplo devuelve un objeto Promise , que es una determinada acción realizada por la función. Una llamada al método resolve() indica a la promesa que su operación se completó con éxito. En tales construcciones, también se usa el método de promesas .then() ; con su ayuda, después de resolver con éxito la promesa, puede ejecutar una determinada devolución de llamada. Se .catch() método .catch() si algo salió mal durante el trabajo de la promesa.

Funciones asincrónicas


Las funciones declaradas usando la async asíncrona (funciones asincrónicas) nos dan la oportunidad de escribir código que esté limpio y no sobrecargado con construcciones de servicio, lo que nos permite obtener el mismo resultado que obtuvimos usando promesas. Cabe señalar que la async es esencialmente solo "azúcar sintáctico" para las promesas.

Las funciones asincrónicas se crean utilizando la palabra clave async al declarar una función. Se ve así:

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

Las funciones asincrónicas se pueden pausar usando la palabra clave await . Solo se puede usar en funciones asincrónicas. Le permite devolver el resultado de la función asincrónica, que estará disponible después de que dicha función complete la ejecución de una tarea.

Compare el funcionamiento de una función asincrónica y una promesa que devuelve una cadena:

 //   const asyncGreeting = async () => 'Greetings'; //  const promiseGreeting = () => new Promise(((resolve) => { resolve('Greetings'); })); asyncGreeting().then(result => console.log(result)); promiseGreeting().then(result => console.log(result)); 

Es fácil ver que el uso de la async permite escribir código asincrónico que parece síncrono. Es mucho más fácil trabajar con este código.

Ahora que hemos cubierto las cosas básicas, pasemos a nuestro ejemplo.

Conversor de divisas


▍ Preparación preliminar


Aquí crearemos una aplicación simple pero cognitiva desde el punto de vista del estudio de la construcción de aplicaciones asíncronas / en espera. Es un convertidor de divisas que utiliza datos reales obtenidos de las API correspondientes. El programa acepta la cantidad en una determinada moneda, el código de esta moneda, así como el código de moneda en el que queremos convertir esta cantidad. Después de eso, el programa muestra el resultado descargando primero los datos actuales sobre los tipos de cambio. El programa también muestra una lista de países en los que puede gastar dinero en la moneda a la que se transfiere la cantidad especificada.

En particular, aquí vamos a utilizar datos de dos fuentes de información asincrónicas:

  1. Servicio de Currencylayer.com . En este sitio, deberá crear una cuenta gratuita y obtener una clave para acceder a la API (clave de acceso API). Desde aquí tomaremos los datos necesarios para la conversión de la cantidad de una moneda a otra.
  2. Servicio restcountries.eu . Se puede usar sin registro. Desde aquí, cargamos datos sobre dónde puede usar la moneda en la que convertimos la cantidad de dinero especificada.

Cree un nuevo directorio y ejecute el comando npm init en él. Cuando el programa nos haga una pregunta sobre el nombre del paquete que se está creando, presentaremos currency-converter . No puede responder otras preguntas del programa presionando Enter como respuesta. Después de eso, instale el paquete Axios en nuestro proyecto ejecutando el npm install axios --save en su directorio. Cree un nuevo archivo llamado currency-converter.js .

Comencemos a escribir el código del programa conectando Axios en este archivo:

 const axios = require('axios'); 

Nuestro proyecto tendrá tres funciones asincrónicas. El primero cargará los datos de la moneda. El segundo cargará los datos del país. El tercero recopilará estos datos, los presentará en una forma fácil de usar y los mostrará en la pantalla.

▍ La primera función es la carga asincrónica de datos de moneda


getExchangeRate() una función asincrónica getExchangeRate() que tomará dos argumentos: fromCurrency y toCurrency :

 const getExchangeRate = async (fromCurrency, toCurrency) => {} 

En esta función necesitamos cargar datos. Al utilizar la construcción async / await, puede escribir los datos recibidos directamente en una determinada variable o constante. Antes de escribir el código para esta función, no olvide registrarse en el sitio y obtener una clave de acceso API. Para cargar datos, necesitamos la siguiente construcción:

 const response = await axios.get('http://www.apilayer.net/api/live?access_key=[    API]'); 

Después de recibir la respuesta del sistema, los datos que necesitamos se pueden encontrar en el objeto de response.data.quotes en response.data.quotes . Aquí está el fragmento del objeto con los datos que nos interesan (es visible en el 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 el objeto con tasas de cambio en la constante de rate :

 const rate = response.data.quotes; 

El código de moneda base se puede encontrar en response.data.source . Escribimos el código de la moneda base en la moneda base constante:

 const baseCurrency = response.data.source; 

Dado que, por defecto, los datos devueltos por esta API son el tipo de cambio frente al dólar estadounidense (USD), crea un usd constante, en el que escribimos el resultado de dividir 1 por el tipo de cambio en el que se especifica la cantidad:

 const usd = 1 / rate[`${baseCurrency}${fromCurrency}`]; 

Presta atención a cómo se forma la clave, según la cual obtenemos el valor del curso. En el objeto obtenido de la API, cuyo fragmento se da arriba, las claves son cadenas que comienzan con USD y terminan con el código de la moneda correspondiente. Como se supone que nuestro programa acepta códigos de moneda de cadena, generamos una clave concatenando una cadena que contiene el código de moneda base y lo que se pasa a la función en el parámetro fromCurrency .

Ahora, para obtener la tasa de cambio de fromCurrency a toCurrence , multiplicamos la constante usd por la tasa de toCurrency . Se ve así:

 const exchangeRate = usd * rate[`${baseCurrency}${toCurrency}`]; 

Como resultado, devolveremos lo que entra en exchangeRate . Así es como se ve su 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}`);   } }; 

Tenga en cuenta que la construcción regular try / catch se usa para manejar los errores que pueden ocurrir durante la ejecución de la consulta.

▍ La segunda función es la carga asincrónica de los datos del país.


Nuestra segunda función, getCountries() , que carga asincrónicamente información sobre países en los que puede usar la moneda a la que convertiremos la cantidad especificada en otra moneda, tomará el argumento currencyCode :

 const getCountries = async (currencyCode) => {} 

Para cargar datos, utilizamos el siguiente comando:

 const response = await axios.get(`https://restcountries.eu/rest/v2/currency/${currencyCode}`); 

Si, por ejemplo, usamos el código HRK (kuna croata) en la solicitud, recibiremos un código JSON en respuesta, un fragmento del cual se muestra a continuación:

 [   {     "name":"Croatia", ...  } ] 

Es un conjunto de objetos con información sobre países. Las propiedades de name de estos objetos contienen el nombre del país. Puede acceder a esta matriz utilizando la construcción response.data . Aplicamos el método de matriz map() para extraer los nombres de países de los datos recibidos y devolver estos datos de la función getCountries() , que será una matriz de nombres de países:

 return response.data.map(country => country.name); 

Aquí está el getCountries() completo de la función 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}`);   } }; 

▍Tercera función: recopilación y salida de datos


Nuestra tercera función asincrónica, convertCurrency () , aceptará los argumentos de fromCurrency , toCurrency y amount - códigos de moneda y cantidad.

 const convertCurrency = async (fromCurrency, toCurrency, amount) => {} 

En él, primero obtenemos el tipo de cambio:

 const exchangeRate = await getExchangeRate(fromCurrency, toCurrency); 

Luego cargamos la lista de países:

 const countries = await getCountries(toCurrency); 

A continuación, realizamos la conversión:

 const convertedAmount = (amount * exchangeRate).toFixed(2); 

Y después de que se recopilan todos los datos necesarios, devolvemos la línea que verá el usuario del programa:

 return `${amount} ${fromCurrency} is worth ${convertedAmount} ${toCurrency}. You can spend these in the following countries: ${countries}`; 

Aquí está el código de función completo:

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

Tenga en cuenta que esta función no tiene un bloque try / catch, ya que solo funciona con los resultados proporcionados por las dos funciones descritas anteriormente.

▍Inicie el programa


Hemos preparado tres funciones, dos de las cuales cargan datos de varios servicios, y una recopila estos datos y los prepara para la salida. Ahora solo necesitamos llamar a esta función, pasándole todo lo que necesitamos. Aquí no implementaremos mecanismos que permitan llamar a nuestro programa desde la línea de comando con la transferencia de moneda y códigos de suma, aunque puede hacerlo si lo desea. Simplemente llamamos a la función convertCurrency() , pasándole los datos necesarios:

 convertCurrency('EUR', 'HRK', 20)   .then((message) => {     console.log(message);   }).catch((error) => {     console.log(error.message);   }); 

Aquí queremos saber cuánto kuna croata se puede cambiar por 20 euros y en el camino para saber en qué países se puede gastar este dinero.

Llamamos al programa ingresando el siguiente comando en la terminal:

 node currency-converter.js 

En respuesta, obtenemos lo siguiente.


El resultado del programa.

Aquí, por si acaso, el código completo de nuestro proyecto.

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

Resumen


Esperamos que este ejemplo del uso de la construcción asíncrona / espera en condiciones reales haya ayudado a aquellos que no entendieron esta construcción antes de resolverla.

Estimados lectores! Si usa la construcción async / await en la práctica, comparta sus impresiones al respecto.

Source: https://habr.com/ru/post/es436884/


All Articles