¿Qué es una Promise en Javascript?

Cuando empecé a programar Javascript, uno de los conceptos con los que más dificultad tuve en comprender es el de las promesas, o Promises, en inglés. A pesar de leer diferentes definiciones que encontraba en la red y de que un par de desarrolladores experimentos me lo explicaron, me tomó tiempo asimilarlo.

Ahora que comprendo que es un Promise, trataré de explicártelo de la manera más sencilla posible, con ejemplos.

Entonces, ¿qué es un Promise en Javascript? El objeto Promise representa la eventual finalización (o falla) de una operación asincrónica y su valor resultante. O dicho de una manera más simple y menos técnica, una promesa es un objeto que puede devolverte algún valor o una falla en el futuro.

¿En el futuro? Si, hay que tomar en cuenta el factor tiempo.

A modo de ilustración, imagínate que estás en un restaurante y le pides al mesero una pizza de champiñones. ¿Verdad que la pizza no aparece inmediatamente? El mesero se va de tu mesa y se dirige a la cocina; varios minutos después, regresa a tu mesa, con uno de dos resultados:

  1. Te sirve la pizza de champiñones que pediste 🍕
  2. Te dice que ya no tienen pizza de champiñones 🥺

Puede decirse que esto es un tipo de “promesa”, porque se espera que el mesero regrese con alguna respuesta.

De la misma manera, con Javascript uno puede, por ejemplo, enviar una solicitud de HTTP a un API, pero el resultado no lo obtienes al instante. Sino que algún tiempo después, tal vez un segundo más adelante, recibes la respuesta del API.

Dos posibles resultados podrían ser:

  1. El valor que solicitaste ✅
  2. Una falla o error ❌
Una imagen de un front-end pidiendo y recibiendo datos de un back-end
Una imagen de un front-end pidiendo y recibiendo datos de un back-end

¿Para qué sirven las promesas en Javascript?

Puede que te preguntes: ¿qué nos aporta el objeto Promise de Javascript? El beneficio que aportan las promesas es trabajar con operaciones asíncronas. La programación asíncrona permite a un programa iniciar una tarea de cierta duración y continuar respondiendo a otros eventos mientras esa tarea se ejecuta. De esta manera, el programa no tiene que esperar a que la tarea de larga duración termine para seguir ejecutando código.

¿Cuáles son algunos ejemplos de operaciones asíncronas?

  • una llamada a un endpoint de un API o
  • una consulta (query) a una tabla de una base de datos

Ambas tareas tomarán varios milisegundos o hasta varios segundos en completarse, es decir, son tareas que tardaran cierta duración en devolver un valor.

En fin, la mejor manera de comprender qué son las promesas en Javascript es con código.

¿Cómo se hace un Promise en Javascript?

Aquí tienes un ejemplo sencillo donde se emplea el método estático Promise.resolve(value) para devolver una promesa que retorna el valor dado.

// creamos una promesa y se resuelve exitosamente
const promise = Promise.resolve('hola');

promise
  // qué hacer si la promesa se resuelve exitosamente
  .then(function (result) {
    console.log(result); //👉 hola 
  })
  // qué hacer si ocurre un error
  .catch(function (error) {
    console.error(error);
  });

Otra manera de hacer una promesa en Javascript, pero utilizando el constructor de Promise es la siguiente:

const promise = new Promise(function (resolve, reject) {
  // exito
  resolve('hola');
});

He aquí un ejemplo simple donde se emplea de nuevo el método estático Promise.reject(error) para devolver una promesa que retorna un error.

const promise = Promise.reject('no bueno');

promise
  // qué hacer si la promesa se resuelve exitosamente
  .then(function (result) {
    console.log(result); 
  })
  // qué hacer si ocurre un error
  .catch(function (error) {
    console.error(error); //  ❌ no bueno
  });

Comúnmente se utiliza setTimeout para imitar el comportamiento de un API. Este ejemplo es un poco más realista porque vamos a agregar una demora de 3 segundos antes de retornar un resultado.

const promise = new Promise(function (resolve, reject) {
  setTimeout(() => resolve('hola'), 3000);
});

promise.then(
  function (result) {
    // Imprime el resultado a la consola
    // al transcurrir tres segundos
    console.log(result); // ⌚hola
  },
  function (error) {
    console.error(error);
  }
);

Igualmente, podemos devolver un error después de un retraso de 3 segundos.

const promise = new Promise(function (resolve, reject) {
  // error
  setTimeout(() => reject('no bueno'), 3000); // ⌚❌
});

Resolviendo una Promise con fetch en Javascript

Hasta el momento hemos estado creado promesas manualmente y resolviendolas. Es hora de analizar un ejemplo real. Utilicemos la función fetch para obtener datos de un API.

Si no conoces la función fetch, permíteme explicártelo de la manera más concisa y fácil de entender posible. He aquí la sintaxis simplificada de fetch, usando solamente un parámetro:

fetch(url)

La función fetch retornara una promesa que resuelve a un objeto Response.

Vamos a hacer peticiones HTTP a una API pública llamada JSON Placeholder. Es un API que se utiliza para hacer pruebas.

// peticion GET https://jsonplaceholder.typicode.com/todos/1'
const promise = fetch('https://jsonplaceholder.typicode.com/todos/1');

promise
  // retorna un objeto Response y 
  // llamamos el método `json` que, a su vez, retorna una promesa
  .then((response) => response.json()) 
  // entonces tenemos que usar otro .then
  .then((json) => console.log(json));

Se mostrará en la consola algo como lo siguiente:

{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}

¿Notaste que una promesa retornó otra promesa? Esto nos lleva al siguiente concepto: encadenamiento de promesas, o promise chaining, en inglés. También se le conoce como promesas anidadas.

¿Cómo manejar promesas anidadas? 🔗

El encadenamiento de promesas, o promesas anidadas, es una secuencia de tareas asíncronas que deben efectuarse una tras otra. En otras palabras, es una serie de promesas que deben realizarse en orden.

Podemos manejar una serie de promesas utilizando múltiples then.

const promise = fetch('https://jsonplaceholder.typicode.com/todos/1');

promise
  // esta promesa se resuelve primero
  .then((response) => response.json()) // 1️⃣
  // luego se resuelve esta promesa
  .then((json) => console.log(json)); // 2️⃣

En el ejemplo, una promesa depende de otra, es decir, tienes que esperar a que una promesa se haya completado, para que, con su resultado, ejecutar la siguiente. Las promesas se ejecutan en secuencia.

Empleamos el método then para encadenar, por así decirlo, las promesas. Cada llamada a promise.then devuelve una nueva promesa, para luego poder ejecutar el próximo then con ella.

Errores comunes al manejar promesas

Prueba tus habilidades para hacer debugging. 🤓

A continuación analiza el codigo e intenta encontrar la falla antes de leer la explicación.

¿Por qué la promesa resulta en undefined?

const promise = fetch('https://jsonplaceholder.typicode.com/todos/1');

promise
  .then(function(response) {
    response.json(); // ❌ debe tener: return response.json() ✅
  })
  .then(function(json) {
    console.log(json); // 👉 muestra undefined
  });

Una razón por la que parece que una promesa es undefined es porque no se retornó un valor dentro de un then.

¿Por qué el encadenamiento de las promesas parece no funcionar?

const promise = fetch('https://jsonplaceholder.typicode.com/todos/1');

promise.then((response) => response.json());
promise.then((json) => console.log(json));

A veces uno puede caer en el error de agregar varios then a la misma promesa, eso no es encadenamiento.

Similar Posts