# Asincronismo (JavaScript)
## Conceptos Básicos
- 🧵 **Thread**: Thread para Javascript permite realizar programación multihilos en este entorno. En realidad, simula la creación y ejecución de hilos, pero para el desarrollador es lo mismo. Ésto simplifica muchísimo la creación de aplicaciones Javascript.
- 🚫 **Bloqueante**: Una llamada u operación bloqueante no devuelve el control a la aplicación hasta que se ha completado. Por tanto el thread queda bloqueado en estado de espera.
- 🚿 **No bloqueante**: Una tarea no bloqueante se devuelve inmediatamente con independencia del resultado. Si se completó, devuelve los datos. Si no, un error.
- 🎞️ **Síncrono**: Las tareas se ejecutan de forma secuencial, se debe esperar a que se complete para continuar con la siguiente tarea.
- 🚦 **Asíncrono**: Las tareas pueden ser realizadas más tarde, lo que hace posible que una respuesta sea procesada en diferido. La finalización de la operación I/O (entrada/salida) se señaliza más tarde, mediante un mecanismo específico como por ejemplo un callback, una promesa o un evento, lo que hace posible que la respuesta sea procesada en diferido.
- 🛤️ **Paralelismo**: El paralelismo es la ejecución simultánea de dos o más tareas. Algunas tareas se pueden dividir en partes más pequeñas que pueden ser resueltas simultáneamente.
- 🎮 **Concurrencia**: La concurrencia es la capacidad de un algoritmo o programa para ejecutar más de una tarea a la vez. El concepto es similar al procesamiento paralelo, pero con la posibilidad de que muchos trabajos independientes hagan diferentes cosas a la vez en lugar de ejecutar el mismo trabajo.
- 🌀 **Eventloop** o Loop de eventos: El bucle de eventos es un patrón de diseño que espera y distribuye eventos o mensajes en un programa.
## Formas de manejar la asincronía en JavaScript:
- 📩 Callbacks: Una función que se pasa como argumento de otra función y que será invocada.
- 🫱🏼🫲🏾 Promesas: (implementado en ES6) Una promesa es una función no-bloqueante y asíncrona la cual puede retornar un valor ahora, en el futuro o nunca.
- 🛣️ Async / Await: (implementado en ES2017) Permite estructurar una función asincrónica sin bloqueo de una manera similar a una función sincrónica ordinaria.
⏲️ Un ejemplo fácil de asincronismo vs sincronismo es invitar a unos amigos a una fiesta y ofrecer una parrillada. Primero decides colocar la carne y verduras a la parrilla y luego repartir bebidas y algo para picar (snacks). Si fuera una persona síncrona (Blocking) tendrías que esperar a que la comida de la parrilla esté cocinada y luego atender a los invitados. Pero si fuera una persona asíncrona (Non Blocking) luego de poner la carne al carbón, sacas las bebidas frías de la nevera y compartes con los invitados mientras se cocina la carne. La acción de que la comida en la parrillada esté lista sería un callback que está esperando que finalice el proceso para ejecutarse. Pero otros procesos (como compartir la velada con bebidas y algo de picar) ya podrían irse realizando.
## Callbacks
Un Callback es una una función que se pasa como argumento de otra función y que será invocada.
*Ejemplo*
```javascript=
function sum(num1, num2) {
return num1 + num2;
}
function rest(num1, num2) {
return num1 - num2;
}
function mult(num1, num2) {
return num1 * num2;
}
function div(num1, num2) {
return num1 / num2;
}
function calc(num1, num2, callback) {
return callback(num1, num2);
};
// Calcular suma
calc(1,2,sum)
```
## XMLHttpRequest
XMLHttpRequest es un objeto de JS que permite hacer peticiones hacia servicios en la nube(URLs o APIs).
Existen 5 estados en un llamado XMLHttpRequest:
- 0 → Se ha inicializado.
- 1 → Loading (cargando).
- 2 → Se ha cargado.
- 3 → Procesamiento si existe alguna descarga.
- 4 → Completado.
#### Métodos y propiedades:
- **xmlhttp.open()** → Prepara la petición para ser enviada tomando tres parámetros: prótocolo, url, asíncrono (true).
- **xmlhttp.readyState** → Retorna el estado de la petición.
- **xmlhttp.onreadystatechange** → Un eventHandler que es llamado cuando la propiedad readyState cambia.
- **xmlhttp.status** → Retorna el estado de la respuesta de la petición. (200,400,500)
- **xmlhttp.send()** → Envía la petición.
*Ejemplo*
```javascript=
const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
const API = 'https://api.escuelajs.co/api/v1';
function fetchData(urlApi, callback) {
let xhttp = new XMLHttpRequest();
xhttp.open('GET', urlApi, true);
xhttp.onreadystatechange = function (event) {
if (xhttp.readyState === 4) {
if (xhttp.status === 200) {
callback(null, JSON.parse(xhttp.responseText));
} else {
const error = new Error('Error' + urlApi);
return callback(error, null);
}
}
}
xhttp.send();
}
fetchData(`${API}/products`, function (error1, data1) {
if (error1) return console.error(error1);
fetchData(`${API}/products/${data1[0].id}`, function (error2, data2) {
if (error2) return console.error(error2);
fetchData(`${API}/categories/${data2?.category?.id}`, function (error3, data3) {
if (error3) return console.error(error3);
console.log(data1[0]);
console.log(data2.title);
console.log(data3.name);
});
});
});
```
Problema CallBack Hell, sobreanidamiento de código.

## Promesas
Las promesas son asíncronas, por lo que el código continuará su ejecución normalmente y luego dirá si la promesa se resolvió o se rechazó. Por lo que varias promesas pueden llegar a entrar en ejecución al mismo tiempo.
Las promesas pueden suceder:
- Ahora
- En el futuro
- Nunca
### Estados
Una promesa puede tener varios estados:
- **Pendiente pending** Una promesa inicia en este estado: no cumplida, no rechazada: Una promesa inicialmente está pendiente.
- **Cumplida fulfilled**: Significa que la operación se completó satisfactoriamente, .then(va => …) Cuando llamamos a resolve entonces la promesa pasa a estar resuelta. Cuando una promesa se resuelve entonces se ejecuta la función que pasamos al método .then
- **Rechazada rejected**: significa que la operación falló, .catch(err => …) Si llamamos a reject pasa a estar rechazada (obtenemos un error que nos va a indicar la razón del rechazo).Si la promesa es rechazada entonces se ejecuta la función que pasamos a .catch
*Ejemplo Promesas*
```javascript=
const sheeps = 20;
const sleep = new Promise((resolve, reject) => {
if(sheeps > 15) {
resolve("You can sleep 😴")
} else {
reject("Just not, count more sheeps! 🐑")
}
})
const sleepAction = () => {
sleep.
then(result => console.log(result)).
catch(err => console.log(err))
}
setTimeout(sleepAction,2000)
```
*Ejemplo API con Promesas*
```javascript=
import fetch from "node-fetch"
const API = 'https://api.escuelajs.co/api/v1'
const postData = (urlApi, data) => {
const response = fetch(urlApi, {
method: "POST",
mode: "cors",
credentials: "same-origin",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
return response
}
const product = {
"title": "New Product 214",
"price": 10,
"description": "A description",
"categoryId": 1,
"images": ["https://placeimg.com/640/480/any"]
}
// POST
postData(`${API}/products`, product)
.then(response => response.json())
.then(data => console.log(data))
.catch(err => console.log(`Error: ${err}`))
// GET
fetch(`${API}/products/214`)
.then(response => response.json())
.then(data => console.log(data))
.catch(err => console.log(`Error: ${err}`))
```
## Async/Await
Este concepto introducido en ES8 nos permite crear funciones asincronas. Pero que es una función asincrona?
La declaración de una función con la palabra reservada async define una función asíncrona que devuelve un objeto, lo cual permite a un programa correr una función sin congelar todo la compilación.
Por lo que de alguna forma podemos simular que estamos tratando código sincrono con Promesas.
Está estructura está compuesta por:
- La palabra **async** antes de la función, hace que la función devuelva una promesa.
- La palabra **await** se utiliza dentro de las funciones async, lo que hace que el programa espere hasta que la variable(promesa) se resuelva para continuar.
*Ejemplo*
```javascript=
const fnAsync = () =>{
return new Promise((resolve, reject) =>{
(true) //se usó operador ternario y se está forzando con true que se cumpla la condición
? setTimeout(() => resolve('Async!!', 2000))
: reject(new Error('Error!')); //arroja "error" en caso de que la condición sea false
});
}
const anotherFn = async () => { //la palabra async es para el cuerpo de la función
//la palabra await estará dentro de la lógica a implementar
const something = await fnAsync(); //aquí nos está regresando una promesa
console.log(something); //se imprime mientras se espera
console.log('Hello!');
}
console.log('Before'); //al ser la primera orden con solo console.log, 'Before' se imprime primero
anotherFn();//es el segundo en llamar, pero aún así no se imprimen los console de su lógica y tarda 2 s en ser ejecutada
console.log('After'); //aparece justo después de 'Before' porque anotherFn() está esperando una promesa y aún así el programa no se detiene, sino que sigue y así tenemos 'After' de segundo al imprimir
/*La salida al correr con Run Code queda:
Before
After
Async!!
Hello!
*/
```
*Async/Await API*
```javascript=
import fetch from "node-fetch"
const API = 'https://api.escuelajs.co/api/v1'
const fetchData = async apiUrl => {
const response = await fetch(apiUrl)
const data = await response.json()
return data
}
const test = async apiUrl => {
try {
const products = await fetchData(`${apiUrl}/products`)
const product = await fetchData(`${apiUrl}/products/${products[0].id}`)
const category = await fetchData(`${apiUrl}/categories/${product.category.id}`)
console.log(products)
console.log(product.title)
console.log(category.name)
} catch (err) {
console.log(err)
}
}
test(API)
```
[FakeAPI](https://fakeapi.platzi.com/)
###### tags: `Platzi` `JavaScript` `Asincronismo`