Consumir promesas

Los métodos then() y catch()


Las promesas en Javascript son un tipo de dato, como lo es un o un . Son un de tipo . Cuando obtengamos uno de estos objetos (generalmente, devuelto por una función) sabemos que tenemos una promesa que puede que se cumpla en un futuro cercano o lejano.

Podemos trabajar con promesas de varias formas. Una de ellas es usar los thennables, donde se utiliza un método llamado .then() (entonces). Observa la siguiente tabla:

Métodos Descripción Más info
.then(resolve) Ejecuta la función cuando la promesa se cumple. (Este artículo)
.catch(reject) Ejecuta la función cuando la promesa se rechaza. (Este artículo)
.then(resolve, reject) Equivale a las 2 anteriores en el mismo .then(). Ver then() + catch()
.finally(end) Ejecuta la función cuando sale de pendiente. Ver finally()

Más adelante veremos, que a diferencia del apartado anterior donde se utilizaban solamente funciones callback, en este enfoque se tiende a no anidar promesas, evitando así el famoso Callback Hell, y haciendo el código mucho más legible.

Recordemos que las promesas estarán siempre en un estado de los siguientes:

  • 1️⃣ pendiente (el estado inicial)
  • 2️⃣ aceptada (se gestiona a través del .then())
  • 2️⃣ rechazada (se gestiona a través del catch())

El método .then()

La forma general de consumir una promesa es utilizando el .then(). Antes de empezar, ten en cuenta que vamos a utilizar la función asíncrona fetch(), que sirve para hacer peticiones y traernos archivos desde una dirección URL concreta:

fetch("/robots.txt");   // Promise { <pending> }

Observa que al ejecutar esa función, en lugar de bloquear la ejecución a la espera de devolver el contenido del archivo que hemos pedido, lo que hace es devolver una promesa . La promesa se devuelve en su estado inicial (pendiente), y con el tiempo es posible (no es seguro) se cumplirá, se rechazará o se quedará en estado pendiente de forma indefinida.

Hasta ahora, solo hemos ejecutado la función, pero no hemos tratado la promesa. Para manejarla, utilizaremos la mencionada función .then() que existe en cualquier promesa. Dicha función recibe un parámetro, que es la función que se ejecutará cuando la promesa se cumpla:

fetch("/robots.txt").then(function() {
  /* Código a realizar cuando se cumpla la promesa */
});

En este caso, la función fetch() devuelve una promesa que se cumple cuando el navegador obtiene la información solicitada. Cada función asíncrona tiene una condición concreta para que se cumpla la promesa que devuelve, y depende de la implementación del método.

Sin embargo, observa que la función callback no tiene ningún parámetro. Normalmente si que los tiene, y contienen la información que devuelve la promesa cuando se cumple.

Además, observa que he indentado el .then() para que se lea mejor:

fetch("/robots.txt")
  .then(function(response) {
    // response: petición de respuesta del recurso solicitado
  })

El método .catch()

Además de todo lo explicado, es una buena práctica utilizar también el método .catch(), que al contrario que el método .then(), este método ejecutará la función callback pasada por parámetro cuando la promesa se rechaza:

fetch("/robots.txt")
  .then(function() {
    /* Código a realizar cuando se cumpla la promesa */
  })
  .catch(function() {
    /* Código a realizar cuando se rechaza la promesa */
  });

Recuerda que esas funciones callback sólo se ejecutarán en el caso de que se cumpla o rechace la promesa.

Código no bloqueante

Algo muy importante que no se debería pasar por alto, es que el código que hemos ejecutado en los ejemplos anteriores es un código asíncrono no bloqueante.

  • Asíncrono: Porque generalmente no se ejecuta de inmediato, sino que tardará en completarse.
  • No bloqueante: Porque mientras espera ser ejecutado, no bloquea y continua el resto del programa.

¿Qué significa esto? Significa que cuando llegamos a un .then(), el sistema no se bloquea, sino que deja la función «pendiente» hasta que se cumpla o rechace la promesa. Mientras esto no ocurra, se continuará procesando y ejecutando el resto del programa.

Observa el siguiente ejemplo:

fetch("/robots.txt")
  .then(response => {
    console.log("Código asíncrono");
  });

console.log("Código síncrono");

Aunque el console.log("Código asíncrono") figura unas líneas antes del console.log("Código síncrono"), no se garantiza que se muestre antes, de hecho, normalmente aparecerá después. Esto ocurre porque el console.log() del interior del .then() no ocurre inmediatamente, y al no ser bloqueante, se continua con el resto del programa hasta que la promesa de la operación asíncrona se cumpla o rechace, procesando su .then() o .catch(), y volviendo a continuar el resto del programa por donde iba.

Las promesas en JavaScript, tanto gestionadas con then() como con async/await (que veremos más adelante) son no bloqueantes. Sin embargo, con async/await, la ejecución dentro de la función async se "pausa" en los puntos donde se utiliza await, aunque el resto del programa sigue siendo no bloqueante.

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev