Páginas

Mostrando entradas con la etiqueta promise. Mostrar todas las entradas
Mostrando entradas con la etiqueta promise. Mostrar todas las entradas

lunes, 1 de noviembre de 2021

JavaScript: Ejemplo del método Promise.all()

Este método es útil cuando se han creado varias promesas y es necesario realizar una operación solo cuando se hayan resuelto todas.

El método Promise.all() toma un array de promesas como entrada y devuelve una sola promesa que se resuelve con un array que contiene el resultado de las promesas de entrada. La promesa devuelta se resolverá sólo si todas las promesas de entrada se resuelven se rechazará si alguna es rechazada. El rechazo se resolverá con el mensaje de error de la primera promesa rechazada.

Ejemplo

En este ejemplo se crean 2 promesas que devuelven los resultados en momentos distintos. Una de ellas devuelve el resultado en 2 segundos y la otra en 1 segundo. Con el método all(), se consigue que el resultado no se procese hasta que hayan terminado las dos promesas.

let datosA = new Promise((resolvereject=>
                   {setTimeout(()=> (resolve("datos de A"), 2000))});
let datosB = new Promise((resolvereject=> 
                   {setTimeout(()=> (resolve("datos de B"), 1000))});

Promise.all([datosAdatosB]).then((result=> 
                                {console.log ("datosAyB "result)})

// RESULTADO: datosAyB  [ 'datos de A', 'datos de B' ]

Otro ejemplo

En este ejemplo se requiere rellenar el contenido de las variables datosA y datosB. Las funciones de relleno son promesas que se resuelven de nuevo en tiempos distintos, 1 o 2 segundos. Con el método all() se consigue sincronizar las funciones de rellenado y solo se muestra el contenido de las variables cuando están ámbas rellenas.

let datosA;
let datosB;

let rellenadatosA = new Promise((resolvereject=> 
                            {setTimeout(()=> 
                               {datosA="datos A"resolve(datosA)}, 2000)});
let rellenadatosB = new Promise((resolvereject=> 
                            {setTimeout(() => 
                               {datosB="datos B"resolve(datosB)}, 1000)});

Promise.all([rellenadatosA]).then(() => console.log ("datosAyB "datosAdatosB));

// datosAyB  datos A datos B

Espero que sea de ayuda. Si quedan dudas, dejadlas en comentarios. 

Chao


jueves, 28 de octubre de 2021

Javascript: Otro ejemplo sencillo de callback, promise y async/await

En los comienzos de internet los sitios web ofrecían datos estáticos en páginas HTML. Actualmente las aplicaciones web son interactivas y dinámicas y se ha incrementado la necesidad de hacer operaciones como peticiones en la red para recuperar datos a través de un API. Para manejar estas operaciones en JavaScript, un desarrollador debe usar técnicas asíncronas de programación. JavasScript es un lenguaje de un solo hilo(thread) con un modelo de ejecución síncrono que procesa una operación trás otra y solo puede procesar una instrucción al mismo tiempo. Sin embargo, una acción como pedir datos a un API puede consumir una cantidad tiempo grande dependiendo de la velocidad de la red, la cantidad de datos solicitados y otros factores. Si la llamada a la API se hace de forma síncrona, el buscador no será capaz de manejar las acciones del usuario como hacer scrolling o pulsar un botón hasta que la operación se haya completado. Esto se conoce como blocking. Para evitar que se produzca "blocking", los entornos de browser (Chrome, Firefox, Edge, Opera, Safari, etc.) han desarrollado Web APIs para que desde JavaScript los accesos puedan ser asíncronos, de tal manera que se pueden ejecutar en paralelo con otras operaciones. Esto previene el "blocking" porque el usuario puede seguir interactuando con la página mientras la petición asíncrona se está procesando. Cómo desarrollador de JavaScript es necesario saber como trabajar con las Web APis asíncronas y manejar los datos recibidos de ellas. En este ejemplo, vamos a trabajar con varías técnicas de tratamiento de la asíncronia: callbacks, promesas y async/await. 

EJEMPLO 

Es un módulo que en la función Hello() llama a una función asíncrona setTimeout(). Esta función le asigna el valor 'Buenos días' a la variable greetings al cabo de 1000 milisegundos(1 segundo). La función setTimeout() es asíncrona y no bloqueante porque se lanza su ejecución y el programa continua ejecutando las siguientes instrucciones sin esperar a que setTimeout haya terminado. ¿Qué se puede hacer para controlar el orden en que se ejecutan las sentencias tras la llamada a setTimeout? ¿Qué pasa si setTimeout obtiene algún dato que necesitamos para tomar una decisión en el programa o para mostrarlo en la consola? Veamos: 
 

No se maneja la asincronía (sincronizar1.js)

Cuando se hace el console.log de la variable greetings esta está vacía. La sentencia de asignación se ejecutará después de que se hayan hecho os console logs.
 
let greetings = '';

function hello() {      
  setTimeout(()=>{greetings = 'Buenos Días';}, 1000);  
}

function synchronize(){
  console.log ('\x1b[36m%s\x1b[0m''1- Empieza synchronize');
  hello();
  console.log ('2- greetings está vacio'greetings);
  console.log ('\x1b[36m%s\x1b[0m''3- Acaba synchronize');
}

console.log ('\x1b[31m%s\x1b[0m''0- Empieza módulo');
synchronize();
console.log ('\x1b[31m%s\x1b[0m','4- Acaba módulo');
 
siendo el resultado de la ejecución

 

Se maneja la asincronía con callback (sincronizar2.js)

La función hello(f) tiene un parámetro que representa a una función. Cuando se llama a la función hello se envia como parametro el nombre de la función que muestra el contenido de greetings, así hello(f) puede llamar a la función después de que el valor 'Buenos Dias' se haya asignado a greetings. De esta manera el algoritmo programado se ocupa de que la variable greetings esté rellena antes de ser mostrada.

let greetings = '';

function hello(fdespues) { 
   setTimeout(()=>{
     greetings = 'Buenos Días'fdespues()}, 1000 );  
}

function mostrar(){
    console.log ('2-'greetings)
}

function synchronize(){
  console.log ('\x1b[36m%s\x1b[0m''1- Empieza synchronize');
  hello(mostrar);  
  console.log ('\x1b[36m%s\x1b[0m''3- Acaba synchronize');
}

console.log ('\x1b[31m%s\x1b[0m''0- Empieza módulo');
synchronize();
console.log ('\x1b[31m%s\x1b[0m','4- Acaba módulo');

 siendo el resultado de la ejecución


 Se maneja la asincronía con Promise y then() (sincronizar3.js)

 El objeto Promise se ha diseñado para tratar con funciones asíncronas y dispone de dos parámetros: resolve que representa a una función que indica que todo ha ido bien y la función asíncrona ha terminado con éxito y reject que indica que ha habido algún error. En este módulo la función hello() devuelve una promesa y con el método then() se consigue que el console.log de la variable no se lleve a cabo hasta que la variable tiene el valor asignado. El metodo then() ejecuta la función especificada cuando la promesa ha efectuado un resolve().

let greetings = '';

function hello() { 
  return new Promise((resolvereject=>{    
      setTimeout(()=>{
        greetings = 'Buenos Días';
        resolve();} , 1000 );
  });
}

function synchronize(){
  console.log ('\x1b[36m%s\x1b[0m''1- Empieza synchronize'); 
  hello().then(() => console.log ('2-'greetings));    
  console.log ('\x1b[36m%s\x1b[0m''3- Acaba synchronize');
}

console.log ('\x1b[31m%s\x1b[0m''0- Empieza módulo');
synchronize();
console.log ('\x1b[31m%s\x1b[0m','4- Acaba módulo');

 siendo el resultado de la ejecución


Se maneja la asincronia con async/await (sincronizar4)

Este ejemplo es igual al anterior con la diferencia de que en vez de hacer uso del método then() se hace uso las palabras clave async/await. La palabra clave await se puede usar para llamar a funciones que devuelven promesas. Es el mismo comportamiento que el método then(), hasta que la promesa no se resuelve (resove()) la secuencia de ejecución no continua. Para poder usar await es obligatorio que la función en la que se usar haya sido definida como async.

let greetings = '';

function hello() { 
  return new Promise((resolvereject=>{    
      setTimeout(()=>{greetings = 'Buenos Días';
                      resolve();} , 1000 );
  });

async function synchronize(){
  console.log ('\x1b[36m%s\x1b[0m''1- Empieza synchronize'); 
  await hello();    
  console.log ('2-'greetings);
  console.log ('\x1b[36m%s\x1b[0m''3- Acaba synchronize');
}

console.log ('\x1b[31m%s\x1b[0m''0- Empieza módulo');
synchronize();
console.log ('\x1b[31m%s\x1b[0m','4- Acaba módulo');

 siendo el resultado de la ejecución

 

Sincronizando todo el código (sincronizar5)

En los ejemplos anteriores el console.log ('2- ', greetings) se ejecuta tras el resto de console.log, esto se debe a que lo único que sincroniza el código de los ejemplos anteriores es que se asigne el valor a la variable antes de que esta se muestre en consola. En este ejemplo se sincroniza todo, de manera que los console.log después del de la variable se ejecutan en el orden en que están numerados. Para conseguir esto hacen falta 2 promesas.

let greetings = '';

function hello() { 
  return new Promise((resolvereject=>{    
      setTimeout(()=>{greetings = 'Buenos Días';
                      resolve();} , 1000 );
  });

async function synchronize(){
  return new Promise (async function(resolvereject) {
    console.log ('\x1b[36m%s\x1b[0m''1- Empieza synchronize'); 
    await hello();
    console.log ('2-'greetings);
    console.log ('\x1b[36m%s\x1b[0m''3- Acaba synchronize');
    resolve();
  })
}

console.log ('\x1b[31m%s\x1b[0m''0- Empieza módulo');
synchronize().then(() => console.log ('\x1b[31m%s\x1b[0m''4- Acaba modulo'))

 siendo el resultado de la ejecución

Terminando

Tratar con la asincronía es delicado. Dejo aquí un enlace sobre como funcionan los motores que ejecutan JavaScript. latentflip.com/loupe

Espero que todo esto sea de ayuda y si tenéis alguna pregunta marisaafuera@gmail.com y también el código en https://github.com/MarisaAfuera/morePromisesAsyncAwait




sábado, 28 de noviembre de 2020

JavaScript: Ejemplo de asincronía, callbacks y promises

 Un ejemplo de código asíncrono es:

este código añade al array inicial tres números, el 4, el 5 y el 6. Estos números se añaden en un orden desconocido, el motivo es que la función addToArray hace uso de la función de javascript setTimeout. Esta función ejecuta el array.push después de un tiempo. En el caso del ejemplo el tiempo es elegido al azar por Math.random(). El resultado es que los elementos 4, 5 y 6 no se conoce de antemano en que orden apareceran. A cada ejecución el orden variará: [1, 2, 3, 5, 4, 6] o [1, 2, 3, 6, 4, 5] o cualquier otra combinación.

Utilizando callbacks esto se puede conseguir que los elementos se añadan en orden creciente siendo el resultado siempre [1, 2, 3, 4, 5, 6]. Esto se consigue con:

en este caso aunque addToArray sigue añadiendo los elementos en un tiempo indeterminado, se consigue que 4, 5 y 6 se añadan en el mismo orden siempre. Aquí la llamada a añadir el siguiente número es un callback del número anterior. Esto debido al funcionamiento interno de javascript que gestiona el orden en que se ejecutan las funciones con el stack queue y el callback queue hace que hasta que no se acaba de añadir el 4, no se añada el 5 y hasta que se acaba de añadir el 5 no se añada el 6. La importancia de esta técnica es conseguir sicronía cuando se necesita. Por ejemplo no mostrar una lista desplegable, mientras no tenemos disponibles los datos.

La técnica de callback, pronto se observó que conduce a un código no "limpio" (callback hell). Para evitar esto se ha incluido en javascript un objeto llamado Promise. Este objeto gestiona la asincronía. El ejemplo con Promise queda:

El método then del objeto promise hace que no se ejecute una función hasta que no haya terminado la anterior. Importante hacer notar que la función a controlar, en este caso addToArray debe devolver un objeto Promise para poder utilizar el método then.

Espero que este sencillo ejemplo le pueda ayudar a algún abnegado desarrollador para entender como funcionan las técnicas para manejar la asincronía intrinseca de javascript. 

Queda pendiente async-await para otro post.