Promise - toviddfrei/javascript GitHub Wiki

Tal cual leí las primeras líneas me hice una idea de que podía ser una promesa, en comparación con la vida real, son lo mismo, te prometo hacer una cosa, el tema que a la máquina no le engañas y las promesas no pueden ser no cumplidas, en este caso JavaScript es muy fiable y te hace cumplir tus promesas, vale de similitudes, creo que el concepto está pillado, algo que prometes hacer, que puede prometer hacer un script, estructura, expresión, ahora pasaremos a la sintaxis, lo que sea que escribamos que puede prometer, por ejemplo una conexión a una API o a una base de datos, te he puesto dos ejemplos, pero podríamos extendernos, prefiero dejar que fluya. Quedemos con "prometo realizar..."

Si tenemos en concepto medio claro y por ejemplo nos abstraemos a que somos los desarrolladores de una app que se conecta a varios servicios externos, obtiene unos datos que procesa en servidores propios y luego muestra en sus páginas web automáticas a sus clientes registrados y de pago, valoraremos mucho, pero mucho, mucho las promise, que alguien incluso una máquina te prometa algo y lo cumpla en los tiempos que corren, mmmmmm, y ya no solo que lo cumpla, que te avise de no cumplirlo para que puedas prevenir y tomar medidas, es muy de agradecer, sigamos. Pues si JavaScript, promete, cumple y si no te puedes prevenir, ya que te avisa.

Tenemos que recordar que JavaScript es un lenguaje asíncrono, que quiere decir en pocas palabras, que nos permite organizar como y sobre todo cuando se responderán las llamadas, un ejemplo en una misma página web no todos los scripts terminan de cargar al mismo tiempo, según terminan se muestran, cuando actualizamos una página web y se van cargando viñetas, imágenes, textos, enlaces con apis externas no todo se  muestra en el mismo instante, no es secuencial y si no termina de cargar una galería de imágenes bloquea la página, el enlace a la actualidad meteorológica ya se terminó y si lo muestra, esta situación la hemos visto todos, eso es ser asíncrono, pues bien, las promesas de JavaScript se fundamentan en esta situación, puede ser que en este momento no estés listo, muéstrate cuando termines, y si no avísame del resultado.

Posiblemente, es mucho a asentar de una pasada, quedémonos con varios conceptos claves y vemos un ejemplo, promesa, algo que se completara en un futuro, lenguaje asíncrono, el no completar un proceso, no lo detiene todo, nos avisa del resultado. Estas tres situaciones las tenemos que tener claritas. Vemos un ejemplo.

let conexionApiNueva = new Promise((resolve, reject) => {
    setTimeout(() => {
        //resolve('Resolviendo...')
    }, 1000);

    setTimeout(() => {
        reject(Error('Error return...'))
    }, 1000);
});

conexionApiNueva
    .then(data => {
        console.log(data);
    })
    .catch( err => {
        console.error(err);
    });

Vale, explicamos esto un poco, hemos declarado una variable que realizara un trabajo tal como nos promete o retornara un error avisándonos o si está previsto, que es la cuestión de toda esta explicación, realizara la que esté previsto ante un error posible y mesurado, ahí está el kit de esta cuestión o tema, cuando desarrollamos una promesa, no solo tenemos que tener presente el camino que puede realizar el flujo de datos si es correcto, también tenemos que tener un plan para recoger un posible error, en una promesa si plantea y se prevé ambas posibilidades, por eso y seguimos, vemos que tenemos una variable, que recoge una nueva promesa, pasándole, dos parámetros obligatoriamente, bien o mal, en este caso son palabras reservadas resolve y reject, resolver y rechazar. Hemos preparado a modo de símil la conexión con dos setTimeout simulan el retraso que pudiera tener esa conexión, esto es solo un ejemplo cuando declaramos la nueva promesa y pasamos esos dos parámetros tenemos que ofrecerle tanto el comportamiento si la promesa se resuelve en positivo o si la promesa se resuelve en negativo. Creo que la declaración de la promesa está vista, seguimos y terminamos de ver todo el código.

let conexionApiOld = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('Resolviendo Old...')
    }, 2000);

    setTimeout(() => {
        reject(Error('Error return...'))
    }, 2000);
});

let conexionApiNueva = new Promise((resolve, reject) => {
    resolve('Resolviendo...');
    reject('En duda...');
});

conexionApiOld
    .then(data => {
        console.log(data);
    })
    .catch( err => {
        console.error(err);
    });

conexionApiNueva
    .then(data => {
        console.log(data);
    })
    .catch( err => {
        console.error(err);
    });

Creo que así queda aún más claro, dos promesas una con setTimeout que termina a posterior, JavaScript no tiene problemas en resolver primero la conexión nueva y esperar a resolver la antigua después, lo maneja perfectamente, parece que las promise estén enfocadas exclusivamente a las conexiones externas, enfocadas no diría yo, pero su funcionamiento fundamental es ahí, aparte de que debemos de entender que JavaScript en su naturaleza se basa en la comunicación con servicios externos, por lo tanto, será una tarea ya no diaria, sino al minuto y promise te permite controlar ese trabajo. Vemos un detalle más.

let conexionApiOld = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('Resolviendo Old...')
    }, 2000);

    setTimeout(() => {
        reject(Error('Error return...'))
    }, 2000);
});

let conexionApiNueva = new Promise((resolve, reject) => {
    //resolve('Resolviendo...');
    reject('En duda...');
});

conexionApiOld
    .then(data => {
        console.log(data);
    })
    .catch( err => {
        console.error(err);
    });

conexionApiNueva
    .then(data => {
        console.log(data);
    })
    .catch( err => {
        console.error(err);
    });

Lo dicho, JavaScript es de fiar, si no puede cumplir una promesa te avisa y no se detiene. Esto en una serie de conexiones necesarias para tu aplicación es fundamental para el desarrollo del resto del funcionamiento. Yo lo veo como un soporte para mi caja de herramientas, tal cual el soporte para la taladradora, un complemento esencial en el funcionamiento de cualquier aplicación, si tenemos la capacidad de prever lo que puede pasar, tenemos muchos problemas resueltos de antemano. Profundicemos más, creo que nos vendrá bien a todos.

Vamos a subir un escalón más, tenemos una función que por sí misma nos devuelve una promise y nos proporciona la posibilidad de conectarnos muy fácilmente con apis externas y traernos sus datos, es fetch, es tan fácil como hacer una llamada a una api y guardarla en una variable y a partir de ahí viene lo bueno y lo que comentaremos después de ver un ejemplo. Para este ejemplo he tenido que instalarme una api local, estaba cansado de dedicarle ahora mismo tiempo a conexiones que fallan, que te tienes que autorizar y demás. Bueno, pues he instalado una api local en un momentito con la extensión json-server de Visual Studio, es una anotación o miguita de pan que os dejo, de momento en ese sentido me he solucionado el problema de los test iniciales, de poder romper cosas, poder probar cualquier cosa, lo dicho me lo he hecho cómodo.

Bueno, después del bricoconsejo, seguimos, he instalado mi api, he creado unos datos de prueba que ya he utilizado antes y a seguir, he utilizado fetch para conectar con mi api local y voalaa...

/*
Ejemplo conexion api
Realizamos conexion con api de mi github de pruebas
Intentaremos capturar datos y ve su proceso completo
La herramienta promise es el objetivo fundamental
*/

// Primer promise conexion con la api mimodbland  de github

const conexApiLocal = fetch( ' http://localhost:3000/posts' );

console.log(conexApiLocal);

conexApiLocal
    .then(data => data.json())
    .then(data => {
        data.forEach((element) => {
            console.log(element.tittle);
        });
    })
    .catch(err => {console.error(err)})

/*output
Promise { <pending> }
Loop for
Loops while elemento
Tema a desarrollar
Loops do...while
*/

/*output error
Promise { <pending> }
TypeError: fetch failed
    at node:internal/deps/undici/undici:12502:13
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
  [cause]: AggregateError [ECONNREFUSED]: 
      at internalConnectMultiple (node:net:1117:18)
      at afterConnectMultiple (node:net:1684:7) {
    code: 'ECONNREFUSED',
    [errors]: [ [Error], [Error] ]
  }
}
*/

He pegado ambas salidas, manejando los datos en este caso los tittle y luego manejando el error, vemos como fetch maneja internamente tanto el resolve como el reject, no pensemos que no están, si están, pero fetch los maneja en back, por detrás, hemos reducido nuestro código, tenemos la misma funcionalidad, pero mucho más especifica y a mi entender resulta mucho más fácil establecer una conexión a una api y poderla vigilar.  Una herramienta fundamental y que a la larga nos otorga mucha tranquilidad.

Vamos a ver la última parte de las promise, tal como vemos podemos establecer promesas e ir ejecutándolas una a una, según vayan siendo necesitadas o podemos agruparlas todas y ejecutarlas todas al mismo tiempo, por ejemplo un inicio de sesión de usuario, necesitamos varias promesas, una que conecte con el servidor de autentificación y verifique al usuario, otra que conecte con el servidor de contenido y que según la verificación le otorgue el contenido, y podríamos seguir algunas más, en este caso querríamos ejecutar todas las promise y ver un proceso único digámoslo así. Vale los visualizamos.

const conexionautenticar = new Promise((resolve, reject) =>{
    resolve('Hola, encantado de recibirte');
    reject('No eres usuario de esta web');
  });
  
const conexioncontenido = new Promise((resolve, reject) => {
    resolve('Aqui tienes tu contenido');
    reject('Deseas crear tu panel');
 });
  
const loginActivities = Promise.all([conexionautenticar, conexioncontenido]);
  
loginActivities.then(res => {
    res.forEach(activity => {
      console.log(activity);
    })
})

Bueno, os prometo que más claro lo tengo, nos falta mucho por practicar, pero la promesa sigue en pie me prometo aprender promesas de JavaScript no nos arrepentiremos, vale y un dato para cerrar, todo lo que hemos visto, y todo lo que hemos ejecutado, tenemos que tener muy claro no es por las promesas, las promesas son simple ejecutora, van y vienen con datos, pero si no los traducimos con .then, los guardamos en otros objetos, archivos json, no seriamos capaces de tener una lectura humana de esos datos, tengamos la estructura clara, ya que el funcionamiento está claro.

⚠️ **GitHub.com Fallback** ⚠️