# Clase rápida de programación asíncrona

El código síncrono se ejecuta una linea a la vez, cierto? Entonces si haces esto:

```js
let result = fn()
console.log(result)
```

Vas a tener en tu console el resultado de llamar a `fn`, esto es porque `fn` es una función síncrona, así que cuando se ejecuta, se ejecuta todo el código dentro de `fn`, cuando termina su resultado se guarda en `result` y tu código sigue normal.

El código asíncrono no hace esto, porque justamente es asíncrono.

Entonces si `fn` ahora es una función asíncrona y haces lo mismo que antes (`let result = fn()`) el valor en result no va a ser el resultado de `fn`, si no una promesa.

Obtener una promesas significa "no tengo el resultado todavía, pero cuando lo tenga vas a poder enterarte", como te enterás? haciendo `.then` a la promesa.

```js
let resultPromise = fn()
resultPromise.then(result => {
  // acá tenés el resultado de la promesa
})
```

Si haces un console.log fuera del `.then` no vas a poder obtener el resultado, solo vas a obtener la promesa.

```js
let resultPromise = fn()
resultPromise.then(result => {
  console.log(resultPromise) // este log se ejecuta segundo, con la promesa completa
  console.log(result) // este log se ejecuta tercero, con el resultado de la promesa
})
console.log(resultPromise) // este log se ejecuta primero, con la promesa pendiente
```

En el momento en que haces algo asíncrono ya no podés seguir con un flujo síncrono normal, tu código que dependa del resultado de la promesa, tiene que estar dentro del `.then`.

Alternativamente, podés usar async/await para trabajar con código asíncrono de forma más sencilla:

```js
let result = await fn()
```

Al poner `await` delante de `fn()` lo que haces es decirle al runtime de JS "espera acá hasta que la promesa que devuelve `fn` se complete y después seguí" que es básicamente lo mismo que hacer:

```js
fn().then(result => /* algo acá */)
```
Y es lo mismo que hacer

```js
let resultPromise = fn() // obtenemos la promesa
let result = await resultPromise // esperamos a que se complete la promesa
```

---

Ahora, un componente de React no es y no puede ser asíncrono, por lo que si querés ejecutar una función que devuelve una promesa y usar el resultado en el JSX que renderiza tu componente necesitas mover esa promesa a un useEffect y guardar el resultado en un estado:

```jsx
let [result, setResult] = useState()
useEffect(function getResult() {
  // con esto llamamos a `fn`, esperamos a que se complete la promesa y guardamos el resultado en el estado que creamos arriba
  fn().then(fnResult => setResult(fnResult))
}, [])
// si result es undefined mostras un mensaje de carga, un spinner o algo
if (!result) return <p>Loading results...</p>
// cuando result esté definido lo mostras
return <p>{result}</p>
```

Lo importante acá es que tu componente se va a tener que renderizar dos veces:

1. Se renderiza la primera vez, el estado `result` es undefined, se ejecuta el efecto y se renderiza el `<p>Loading results...</p>`
2. `fn` se completa, se actualiza el estado, esto causa un nuevo render, en este nuevo render `result` tiene un valor (lo que devuelve `fn`), el efecto no se vuelve a ejecutar y se renderiza el `<p>{result}</p>`

Entonces lo importante es que siempre que quieras obtener el resultado de una función asíncrona vas a obtener una promesa, y para obtener el resultado de esa promesa tenés que hacer `fn().then(result => { })` o hacer `let result = await fn()`, nunca deberías hacer `let result = fn(); console.log(result)` porque la función asíncrona no va a estar completa y el resultado no va a estar disponible.