Para terminar de entender la programación asíncrona, vamos a analizar el siguiente código:
let prueba;
prueba = "Hola";
console.log(prueba);
El resultado será: «Hola»
Ahora qué pasa si hacemos algo como esto:
let prueba;
setTimeout(() => {
prueba = "Hola";
}, 1000);
console.log(prueba);
El resultado será undefined.
La diferencia entre ambos es simple, mientras que el primer ejemplo está sincronizado, el segundo no.
En este último, usamos el método setTimeout el cual va a ejecutarse un segundo (1.000 milisegundos) al ser llamado.
Entonces cuando intentamos imprimir el valor de la variable prueba, aún no se le ha asignado un valor, de modo que eso se hará después de un tiempo.
Esa función que se ejecuta en el setTimeout es asíncrono.
Async / Await
Una alternativa con los objetos Promise y luego llamar a los métodos then() y catch() es utilizar funciones asíncronas.
Para crear funciones asíncronas debemos usar la palabra reservada async.
//Función que devuelve una promesa simulada.
const simularPromesa = (nombre, milisegundos, ok) => {
const promesa = new Promise((resolve, reject) => {
setTimeout(() => {
if(ok){
//Una vez finalizada la promesa se ejecutará este código.
resolve("La tarea con el nombre " + nombre + " se ha completado correctamente.");
}else{
//cuando falle la promesa se ejecutará este código.
reject("La tarea con el nombre " + nombre + " NO se ha podido completar correctamente.");
}
}, milisegundos);
});
return promesa;
};
//Función asíncrona que recupera una promesa devuelta por la función simularPromesa.
const ejecutarPromesa = async(nombre, milisegundos, ok) => {
try{
const data = await simularPromesa(nombre, milisegundos, ok);
console.log(data);
}catch(error){
console.log(error);
}
}
ejecutarPromesa("Promesa 1", 3000, true);
ejecutarPromesa("Promesa 2", 3000, false);
En el caso de la palabra await, ésta detendrá la ejecución de la función asincrónica hasta que la promesa se complete.
try / catch
Las sentencias try/catch está son muy comunes en los distintos lenguajes de programación.
Try contendrá un bloque de código que podría llegar a ejecutar un error, mientras catch se va disparar si ese error se produce.
En el caso de las promesas intentaremos recuperar el resultado de la promesa, pero en caso de que falle tendremos que indicarle a nuestro código qué haremos con catch.
Async / Await al consumir un API
En una publicación pasada habíamos vista como recuperar posts del API Json place holder.
html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Ejemplo de DOM</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h1>Ejemplo de listas</h1>
<select id="select_filtro" class="form-select mb-3">
<option value=""> Mostrar todo </option>
<option value="completas"> Mostrar completas </option>
<option value="incompletas"> Mostrar incompletas </option>
</select>
<button type="button" id="btn_mostrar_tareas" class="btn btn-primary mb-3"> Mostrar lista de tareas </button>
<ul id="ul_lista" class="list-group">
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL"
crossorigin="anonymous"></script>
<script src="js/scripts.js"></script>
</body>
</html>
js:
Podemos modificar la función mostrarTareas() por:
mostrarTareas = async() => {
let url = 'https://jsonplaceholder.typicode.com/todos';
if(select_filtro.value == "completas"){
url += '?completed=true';
}else if(select_filtro.value == "incompletas"){
url += '?completed=false';
}
try{
let request = await fetch(url);
let tareas = await request.json();
renderizarTareas(tareas);
}catch(error){
console.log(error);
alert("Surgió un error");
}
}