Crear promesas

Cómo implementar nuestras propias promesas


En los apartados anteriores hemos aprendido que son las promesas y hemos visto como consumirlas utilizando .then(). Sin embargo, esto es sólo una parte de entender las promesas. Ahora nos queda la cuestión opuesta, aprender a implementarlas en nuestras funciones, de modo que devuelvan una promesa y podamos consumirlas posteriormente.

Crear la promesa

Para crear nuestra propia promesa en una función necesitaremos hacer un new Promise(), que generará una promesa. Sin embargo, el new Promise() requiere que se le pase una función callback por parámetro, que de momento la pondremos vacía para simplificar:

const doTask = () => {
  console.log("Mi función");
  const promise = new Promise(() => {});
  return promise;
}

doTask();

Perfecto. Si ejecutamos doTask() veremos que nos devuelve una promesa. Sin embargo, dicha promesa se quedará de forma indefinida en pendiente, porque aún no tiene el código de implementación.

Como hemos mencionado, al new Promise() se le pasa por parámetro una función callback. Dicha función debe tener dos parámetros:

  • El primero, una función callback, resolve, que se usará cuando se cumpla la promesa.
  • El segundo, una función callback, reject, que se usará cuando se rechace la promesa.

Vamos a pararnos aquí y a simplificar un poco el código para entenderlo bien. En primer lugar, hasta ahora estabamos creando una promesa promise y luego revolviéndola. Simplifiquemos y devolvámosla directamente:

const doTask = () => {
  console.log("Mi función");
  return new Promise((resolve, reject) => {

  });
}

doTask();

Además, observa que hemos colocado por parámetro del new Promise() una función con dos parámetros: resolve y reject. Estos dos parámetros son funciones, cuando estemos implementando nuestro código simplemente debemos ejecutar resolve() para cumplir la promesa y reject() para rechazarla.

Implementar la promesa

Ahora toca implementar la promesa. La condición que establezcamos depende del desarrollador. En el caso del fetch() que hemos visto antes, la condición es que se obtengan unos datos remotos (promesa cumplida) o haya un error (promesa rechazada).

En nuestro caso vamos a establecer la tirada de un dado. La promesa será sacar un 6, por lo tanto si ocurre se cumplirá la promesa, pero si no ocurre, se rechazará. Esto es sólo un ejemplo sencillo para entender bien la implementación.

const doTask = () => {
  return new Promise((resolve, reject) => {

    // Obtenemos un número del 1 al 6
    const number = 1 + Math.floor(Math.random() * 6);

    // Si el número es 6, cumplimos la promesa
    if (number === 6) {
      resolve(number)
    }

    // Si no es 6, rechazamos la promesa
    reject(number);
  });
}

En primer lugar, ten en cuenta que la línea donde generamos el número del 1 al 6 suele ser una tarea que no es instantánea como en este caso, sino algo que suele ser más costoso o que tarda más. Sin embargo, para simplificar la explicación estamos realizando esta tarea.

Luego, observa que tanto resolve() como reject() se llaman pasándole por parámetro el número generado. Una vez se llama a uno de ambos, termina la ejecución de la función.

Consumir la promesa creada

Una vez hecho esto, recordemos que ese objeto de resolve() o reject() se devuelve «envuelto en una promesa», permitiendo así al desarrollador consumirla cómodamente más tarde:

doTask()
  .then(number => console.log("¡Objetivo conseguido! ", number))
  .catch(number => console.error("Objetivo no conseguido: ", number));

Ahora imagina que en lugar de implementar el lanzamiento del dado fuera un proceso más costoso que tardara un tiempo considerable, como por ejemplo, obtener un fichero de texto de una página y comprobar si el texto es OK o ERROR. Quizás de esta forma se vea más clara la necesidad de una tarea asíncrona, controlada con promesas, ideal para simplificar código.

¿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