56

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

21772Puntos

hace 7 años

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.

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.

import fs from'fs'import { promisify } from'utils'const readFile = promisify(fs.readFile);

const readMultiFiles = list => {
	const files = JSON.parse(list)
	returnPromise.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.

import fs from'fs'import { promisify } from'utils'const readFile = promisify(fs.readFile);

const readMultiFiles = list => {
	try {
		const files = JSON.parse(list)
		returnPromise.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.

import fs from'fs'import { promisify } from'utils'const readFile = promisify(fs.readFile);

const readMultiFiles = list => {
	try {
		const files = JSON.parse(list)
		returnPromise.all(
			files.map(file => readFile(file, 'utf8')
		)
	} catch (error) {
		returnPromise.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.

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)) thrownewTypeError('The list of files must be a list not a map.')
		returnPromise.all(
			files.map(file => readFile(file, 'utf8')
		)
	} catch (error) {
		returnPromise.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.

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)) thrownewTypeError('The `list` argument must be a list not a map.')
		if (files.length === 0) returnPromise.resolve([])
		returnPromise.all(
			files.map(file => readFile(file, 'utf8')
		)
	} catch (error) {
		returnPromise.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.

Sergio Daniel
Sergio Daniel
sergiodxa

21772Puntos

hace 7 años

Todas sus entradas
Escribe tu comentario
+ 2
Ordenar por:
1
31121Puntos

Nuevamente excelentes tus artículos Sergio Daniel @sergiodxa, me ayudan bastante a entender la asincronía en JAvaScript.

1
6587Puntos

excelente, creo que practicaré más de esto para entenderlo mejor, muchas gracias, Dios los bendiga Platzi.

0
12269Puntos

Excelentes tus artículos Sergio, muchas gracias por compartirlos.