Do you want to switch to Platzi in English?
Tu lugar en PlatziLive
Tu lugar en PlatziLive
estamos en vivo
9

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

20657Puntos

hace un año

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

20657Puntos

hace un año

Todas sus entradas
Escribe tu comentario
+ 2
0
8786Puntos

Excelente!

Tengo una duda por que throw new TypeError y no throw new Error?
Devuelve un objeto diferente?
De ser así, cuando debo usar cada uno?

2
20657Puntos
un año

Hay varios formas de crear errores que nos permiten definir tipos específicos de errores, usar new Error te da un error genérico mientras que TypeError indica que el error es debido a un tipo de dato incorrecto.

Al ver el error en consola se muestra el tipo de error (Error, TypeError, etc.) y nos ayuda a identificar que fue lo que pasó. Te recomiendo leer sobre los errores en MDN

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error

0

Me encantó! Estoy haciendo un curso de Programador Web y me suma mucho leer artículos como este! Gracias por compartirlo!