Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Promesas

Contenidos
  1. Una promesa
  2. Varias promesas
    1. Promesas en serie
    2. Promise.all
    3. Promise.race
  3. Promesas y Microtasks

Una promesa

Las promesas en JavaScript son un objeto que representa la terminación o el fracaso eventual de una operación asíncrona. Una promesa tiene tres estados posibles: pendiente, cumplida y rechazada. Una vez que una promesa cambia a un estado, ya no puede cambiar de estado.

Una promesa se crea utilizando el constructor Promise, el cual recibe una función que se ejecuta inmediatamente con dos argumentos: resolve y reject. La función debe llamar a resolve cuando la operación asíncrona se completa con éxito, o a reject si hay algún error.

Una vez que una promesa se ha cumplido o rechazado, se pueden añadir controladores de eventos utilizando los métodos then y catch, los cuales reciben funciones que se ejecutan cuando la promesa se cumple o se rechaza respectivamente.

Por ejemplo:

 
let promise = new Promise(function(resolve, reject) {
  let random = Math.random()

  if (random > 0.5) {
    resolve('Success!')
  } else {
    reject('Error')
  }
});

promise
.then(function(result) {
  console.log(result)
})
.catch(function(error) {
  console.log('Error: ' + error)
})

En este ejemplo, creamos una promesa que se cumple con el mensaje “Success!”. Añadimos un “controlador de eventos” then() para mostrar el resultado cuando la promesa se cumple y uno catch() para mostrar el error si algo falla.

Varias promesas

Es frecuente que debamos ejecutar varias operaciones asíncronas en diferentes contextos. En ocasiones necesitamos que sea en forma secuencial (o en serie) y en otras se necesita que sea en paralelo.

Promesas en serie

Se pueden encadenar promesas en JavaScript. Una vez que se tiene una promesa, se puede utilizar el método then() para especificar qué debe suceder cuando se cumple la promesa, y utilizar el método catch() para especificar qué debe suceder cuando se rechaza la promesa.

Cada vez que se llama al método then() o catch() se devuelve una nueva promesa, de modo que se pueden encadenar varios métodos then() o catch() juntos para crear una cadena de promesas.

Promise.all

El método Promise.all() permite esperar a que se cumplan varias promesas al mismo tiempo y devuelve una nueva promesa que se cumple con un array que contiene los resultados de las promesas originales en el orden en que se pasaron como argumentos. Si alguna de las promesas originales es rechazada, la promesa devuelta por Promise.all() también será rechazada.

Por ejemplo, digamos que queremos hacer varias peticiones HTTP a diferentes URLs y esperar a que se completen todas antes de continuar con el procesamiento de los datos:

En este ejemplo estamos haciendo 3 peticiones HTTP a diferentes URLs, utilizando el método fetch(). Estamos pasando estas tres promesas al método Promise.all(). Una vez que todas las promesas se cumplen, el método then() se ejecuta con un array de las respuestas. En caso de que alguna de las promesas sea rechazada, se ejecutará el bloque de código del método catch() y se mostrará el error en consola.

Promise.race

El método Promise.race() es similar al método Promise.all(), pero en lugar de esperar a que se cumplan todas las promesas, devuelve una nueva promesa que se cumple o se rechaza tan pronto como una de las promesas originales se cumpla o se rechace. El valor o el error de la promesa cumplida o rechazada se pasa a la promesa devuelta.

Por ejemplo, digamos que queremos hacer varias peticiones HTTP a diferentes URLs y queremos recibir la primera respuesta que recibimos sin importar si es un error o exitosa:

En este ejemplo estamos haciendo 3 peticiones HTTP a diferentes URLs, utilizando el método fetch(). Estamos pasando estas tres promesas al método Promise.race(). Una vez que una de las promesas es cumplida o rechazada, el método then() o catch() se ejecuta con la respuesta o el error de la promesa cumplida o rechazada. En resumen, Promise.race() espera a que se cumpla la primera promesa que cumpla o rechace, y no se preocupa por el estado de las otras promesas.

Promesas y Microtasks

Como vimos anteriormente las promesas están pensadas para registrar callbacks que luego serán ejecutados una vez la Promesa haya sido resuelta o rechazada.

Pero, ¿Qué sucede si hay otros callbacks registrados como por ejemplo a través de setTimeout ?

Acá es donde aparece el concepto de Macro y Micro Tasks.

Las promesas, las microtasks y macrotasks están relacionadas en el procesamiento de tareas asíncronas en JavaScript.

Las microtasks son tareas que se ejecutan antes de la próxima iteración del Event Loop. Las microtasks incluyen tareas como las promesas resueltas y las operaciones de limpieza que se ejecutan después de una operación asíncrona.

Las Macrotasks son tareas que tienen una duración más larga y se ejecutan después de una iteración completa del Event Loop. Las Macrotasks incluyen tareas como el procesamiento de eventos, como clics en un botón o la descarga de un recurso externo.

Cuando una promesa se resuelve, se agrega a la cola de microtasks para su ejecución. Esto significa que las tareas asociadas con la promesa se ejecutarán antes de cualquier otra macrotask en la próxima iteración del Loop de Eventos. De esta manera, se asegura que los resultados de la promesa estén disponibles para su uso en la siguiente iteración.

Luego tenemos la API queueMicrotask() que nos permitirá agregar a la cola de MicroTasks una callback en específico.

En el siguiente ejemplo podemos ver como se priorizan las tareas agrupadas en Macrotasks (ejecución de setTimeout) y Microtasks (representadas por la resolución de las promesas) donde vemos claramente que las Micro tasks tendrán mayor prioridad.

En este caso la promesa que está encadenada tendrá menos prioridad que el callback registrado en queueMicrotask() debido que primero se debe ejecutar ese callback para saber si el siguiente callback que se va a llamar será de una función .then o .catch

Si quieres ver de forma más gráfica y mucho mejor explicado como funciona todo esto, te recomendamos revises la charla de Wekoslav Stefanovsky en la JSConf 2023 en Chile