# Mezclando flujos síncronos y asíncronos usando promesas en JavaScript

Manejar flujos de datos síncronos es fácil, con Async/Await también es fácil
hacerlos asíncronos. Pero qué pasa si tenemos una función que debe realizar
cierta lógica síncrona y luego asíncrona y devolver una promesa. Si esta lógica
síncrona falla, ¿qué ocurriría?

Si todo está bien obtenemos una promesa que se resuelve con el resultado, si hay
un error en la parte asíncrona obtenemos una promesa que se rechaza y vemos el
error. Pero si el error ocurre en la parte síncrona entonces obtenemos un error
normal y no una promesa.

```js
const promesa = readMultiFiles();

// si promesa da un error síncrono todo lo de abajo se rompe
promesa.then(data => console.log(data)).catch(error => console.error(error));
```

Vamos a ver como podemos evitar esto y mezclar estos dos flujos síncronos y
asíncronos. Para eso vamos a crear una función que recibe un string con una
lista de rutas de archivos, vamos a convertir ese string en un array y luego
leer todos esos archivos del disco.

```js
import fs from 'fs'
import { promisify } from 'utils'

const readFile = promisify(fs.readFile);

const readMultiFiles = list => {
  const files = JSON.parse(list)
  return Promise.all(
    files.map(file => readFile(file, 'utf8')
  )
}
```

Esa es nuestra función, ese `JSON.parse` se puede romper si mandamos un dato
inválido en el parámetro `list`. Vamos a meter entonces un `try/catch`.

```js
import fs from 'fs'
import { promisify } from 'utils'

const readFile = promisify(fs.readFile);

const readMultiFiles = list => {
  try {
    const files = JSON.parse(list)
    return Promise.all(
      files.map(file => readFile(file, 'utf8')
    )
  } catch (error) {
    // hacemos algo con el error
  }
}
```

Por ahora no hicimos nada con el error. Lo que vamos a hacer es usar un método
estático del objeto `Promise` para crear una promesa que ya este rechazada. Eso
se hace gracias a `Promise.reject` a la cual le pasamos un objeto error y nos
devuelve una promesa automáticamente rechazada.

```js
import fs from 'fs'
import { promisify } from 'utils'

const readFile = promisify(fs.readFile);

const readMultiFiles = list => {
  try {
    const files = JSON.parse(list)
    return Promise.all(
      files.map(file => readFile(file, 'utf8')
    )
  } catch (error) {
    return Promise.reject(error)
  }
}
```

¡Con eso si ocurre un error síncrono nuestra función va a igualmente devolver
una promesa! Genial, ahora vamos a ver algo: ¿Qué pasa si `list` contiene un
objeto? Si el valor es por ejemplo `"{}"` entonces no va a dar error al hacer el
`JSON.parse`. Podemos validar esto con una condición y devolver un error
personalizado.

```js
import fs from 'fs'
import { promisify } from 'utils'

const readFile = promisify(fs.readFile);

const readMultiFiles = list => {
  try {
    const files = JSON.parse(list)
    if (!Array.isArray(files)) throw new TypeError('The list of files must be a list not a map.')
    return Promise.all(
      files.map(file => readFile(file, 'utf8')
    )
  } catch (error) {
    return Promise.reject(error)
  }
}
```

Luego podemos agregar otra validación para que si `files` está vacío
directamente, devolvemos una promesa resuelta con una lista vacía. Eso lo
hacemos con otro método estático `Promise.resolve` que crea una promesa resuelta
con los datos que le hayamos pasado.

```js
import fs from 'fs'
import { promisify } from 'utils'

const readFile = promisify(fs.readFile);

const readMultiFiles = list => {
  try {
    const files = JSON.parse(list)
    if (!Array.isArray(files)) throw new TypeError('The `list` argument must be a list not a map.')
    if (files.length === 0) return Promise.resolve([])
    return Promise.all(
      files.map(file => readFile(file, 'utf8')
    )
  } catch (error) {
    return Promise.reject(error)
  }
}
```

Con eso acabamos de crear una función que mezcla flujos síncronos y asíncronos,
hace validaciones para devolver algunos errores personalizados o terminar todo .

## Conclusiones

Como vemos gracias a los métodos estáticos `Promise.resolve` y `Promise.reject`
es muy fácil mezclar flujos síncronos y asíncronos y asegurarnos de devolver
siempre promesas y no tener que estar validando tipos de datos.