ES6 - Promesas

Sintaxis de promesa

La sintaxis relacionada con la promesa se menciona a continuación donde, p es el objeto de la promesa, resolve es la función que debe llamarse cuando la promesa se ejecuta correctamente y reject es la función que se debe llamar cuando la promesa encuentra un error.

let p = new Promise(function(resolve,reject){
   let workDone = true; // some time consuming work
      if(workDone){
      //invoke resolve function passed
      
	  resolve('success promise completed')
   }
   else{
      reject('ERROR , work could not be completed')
   }
})

Ejemplo

El ejemplo dado a continuación muestra una función add_positivenos_async()que suma dos números de forma asincrónica. La promesa se resuelve si se pasan valores positivos. La promesa se rechaza si se pasan valores negativos.

<script>   
   function add_positivenos_async(n1, n2) {
      let p = new Promise(function (resolve, reject) {
         if (n1 >= 0 && n2 >= 0) {
            //do some complex time consuming work
            resolve(n1 + n2)
         }
         else
            reject('NOT_Postive_Number_Passed') 
         })
         return p;
   }

   add_positivenos_async(10, 20)
      .then(successHandler) // if promise resolved
      .catch(errorHandler);// if promise rejected

   add_positivenos_async(-10, -20)
      .then(successHandler) // if promise resolved
      .catch(errorHandler);// if promise rejected

   function errorHandler(err) {
      console.log('Handling error', err)
   }
   function successHandler(result) {
      console.log('Handling success', result)
   }

   console.log('end')
</script>

La salida del código anterior será la que se menciona a continuación:

end
Handling success 30
Handling error NOT_Postive_Number_Passed

Encadenamiento de promesas

Promises chaining se puede utilizar cuando tenemos una secuencia de asynchronous taskspara hacerse uno tras otro. Las promesas están encadenadas cuando una promesa depende del resultado de otra promesa. Esto se muestra en el siguiente ejemplo

Ejemplo

En el siguiente ejemplo, add_positivenos_async() functionagrega dos números de forma asincrónica y rechaza si se pasan valores negativos. El resultado de la llamada de función asíncrona actual se pasa como parámetro a las siguientes llamadas de función. Anote cadathen() El método tiene una declaración de retorno.

<script>   
   function add_positivenos_async(n1, n2) {
      let p = new Promise(function (resolve, reject) {
         if (n1 >= 0 && n2 >= 0) {
            //do some complex time consuming work
            resolve(n1 + n2)
         }
         else
            reject('NOT_Postive_Number_Passed')
      })
      return p;
   }

   add_positivenos_async(10,20)
   .then(function(result){
      console.log("first result",result)
      return add_positivenos_async(result,result)
   }).then(function(result){
   console.log("second result",result)
      return add_positivenos_async(result,result)
   }).then(function(result){
      console.log("third result",result)
   })

   console.log('end')
</script>

La salida del código anterior será como se indica a continuación:

end
first result 30
second result 60
third result 120

A continuación, se analizan en detalle algunos métodos de uso común del objeto de promesa:

promesa.todos ()

Este método puede ser útil para agregar los resultados de múltiples promesas.

Sintaxis

La sintaxis de promise.all() El método se menciona a continuación, donde, iterablees un objeto iterable. Por ejemplo, Array.

Promise.all(iterable);

Ejemplo

El ejemplo que se muestra a continuación ejecuta una serie de operaciones asincrónicas [add_positivenos_async(10,20),add_positivenos_async(30,40),add_positivenos_async(50,60)]. Cuando se completan todas las operaciones, la promesa se resuelve por completo.

<script>   
   function add_positivenos_async(n1, n2) {
      let p = new Promise(function (resolve, reject) {
         if (n1 >= 0 && n2 >= 0) {
            //do some complex time consuming work
            resolve(n1 + n2)
         }
         else
            reject('NOT_Postive_Number_Passed')
      })

      return p;
   }
   //Promise.all(iterable)

Promise.all([add_positivenos_async(10,20),add_positivenos_async(30,40),add_positivenos_async(50,60)])
   .then(function(resolveValue){
      console.log(resolveValue[0])
      console.log(resolveValue[1])
      console.log(resolveValue[2])
      console.log('all add operations done')
   })
   .catch(function(err){
      console.log('Error',err)
   })
   console.log('end')
</script>

La salida del código anterior será la siguiente:

end
30
70
110
all add operations done

promesa.raza ()

Esta función toma una serie de promesas y devuelve la primera promesa que se establece.

Sintaxis

La sintaxis de promise.race()La función se menciona a continuación, donde, iterable es un objeto iterable. Por ejemplo, Array.

Promise.race(iterable)

Ejemplo

El ejemplo dado a continuación toma una matriz [add_positivenos_async(10,20),add_positivenos_async(30,40)] de operaciones asincrónicas.

La promesa se resuelve siempre que se completa una de las operaciones de adición. La promesa no esperará a que se completen otras operaciones asincrónicas.

<script>   
   function add_positivenos_async(n1, n2) {
      let p = new Promise(function (resolve, reject) {
         if (n1 >= 0 && n2 >= 0) {
            //do some complex time consuming work
            resolve(n1 + n2)
         } else
            reject('NOT_Postive_Number_Passed')
      })

      return p;
   }

   //Promise.race(iterable)
   Promise.race([add_positivenos_async(10,20),add_positivenos_async(30,40)])
   .then(function(resolveValue){
      console.log('one of them is done')
      console.log(resolveValue)
   }).catch(function(err){
      console.log("Error",err)
   })

   console.log('end')
</script>

La salida del código anterior será la siguiente:

end
one of them is done
30

Promisesson una forma limpia de implementar la programación asíncrona en JavaScript (nueva característica de ES6). Antes de las promesas, las devoluciones de llamada se usaban para implementar la programación asíncrona. Comencemos por comprender qué es la programación asíncrona y su implementación, utilizando Callbacks.

Comprender la devolución de llamada

Una función puede pasarse como parámetro a otra función. Este mecanismo se denominaCallback. Una devolución de llamada sería útil en eventos.

El siguiente ejemplo nos ayudará a comprender mejor este concepto.

<script>   
   function notifyAll(fnSms, fnEmail) {   
      console.log('starting notification process');   
      fnSms();   
      fnEmail();   
   }   
   notifyAll(function() {   
      console.log("Sms send ..");   
   }, 
   function() {   
      console.log("email send ..");   
   });   
   console.log("End of script"); 
   //executes last or blocked by other methods   
</script>

En el notifyAll()En el método que se muestra arriba, la notificación se produce mediante el envío de un SMS y un correo electrónico. Por lo tanto, el invocador del método notifyAll tiene que pasar dos funciones como parámetros. Cada función asume una única responsabilidad como enviar SMS y enviar un correo electrónico.

La siguiente salida se muestra en la ejecución exitosa del código anterior.

starting notification process 
Sms send .. 
Email send .. 
End of script

En el código mencionado anteriormente, las llamadas a funciones son sincrónicas. Significa que el hilo de la interfaz de usuario estaría esperando para completar todo el proceso de notificación. Las llamadas sincrónicas se convierten en llamadas de bloqueo. Entendamos ahora las llamadas sin bloqueo o asíncronas.

Entendiendo AsyncCallback

Considere el ejemplo anterior.

Para habilitar la secuencia de comandos, ejecute una llamada asincrónica o sin bloqueo al método notifyAll (). Usaremos elsetTimeout()método de JavaScript. Este método es asincrónico de forma predeterminada.

El método setTimeout () toma dos parámetros:

  • Una función de devolución de llamada.

  • La cantidad de segundos después de los cuales se llamará al método.

En este caso, el proceso de notificación se ha cerrado con tiempo de espera. Por lo tanto, tomará un retraso de dos segundos, establecido por el código. Se invocará el notifyAll () y el hilo principal seguirá adelante como si se ejecutaran otros métodos. Por lo tanto, el proceso de notificación no bloqueará el hilo principal de JavaScript.

<script>   
   function notifyAll(fnSms, fnEmail) {   
      setTimeout(function() {   
         console.log('starting notification process');   
         fnSms();   
         fnEmail();   
      }, 2000);   
   }   
   notifyAll(function() {   
      console.log("Sms send ..");   
   },  
   function() {   
      console.log("email send ..");   
   });   
   console.log("End of script"); //executes first or not blocked by others   
</script>

La siguiente salida se muestra en la ejecución exitosa del código anterior.

End of script 
starting notification process 
Sms send .. 
Email send ..

En caso de múltiples devoluciones de llamada, el código se verá aterrador.

<script>   
   setTimeout(function() {   
      console.log("one");   
      setTimeout(function() {   
         console.log("two");   
         setTimeout(function() {   
            console.log("three");   
         }, 1000);   
      }, 1000);   
   }, 1000);   
</script>

ES6 viene a rescatarte introduciendo el concepto de promesas. Las promesas son "eventos de continuación" y le ayudan a ejecutar las múltiples operaciones asíncronas juntas en un estilo de código mucho más limpio.

Ejemplo

Entendamos esto con un ejemplo. A continuación se muestra la sintaxis de la misma.

var promise = new Promise(function(resolve , reject) {    
   // do a thing, possibly async , then..  
   if(/*everthing turned out fine */)    resolve("stuff worked");  
   else     
   reject(Error("It broke"));  
});  
return promise;
// Give this to someone

El primer paso para implementar las promesas es crear un método que utilice la promesa. Digamos en este ejemplo, elgetSum()El método es asincrónico, es decir, su operación no debe bloquear la ejecución de otros métodos. Tan pronto como se complete esta operación, luego notificará a la persona que llama.

El siguiente ejemplo (Paso 1) declara un objeto Promise 'var promise'. El Promise Constructor lleva a las funciones primero para la finalización exitosa del trabajo y otro en caso de que ocurra un error.

La promesa devuelve el resultado del cálculo utilizando la devolución de llamada de resolución y pasando el resultado, es decir, n1 + n2

Step 1 - resolver (n1 + n2);

Si getSum () encuentra un error o una condición inesperada, invocará el método de devolución de llamada de rechazo en la Promesa y pasará la información del error a la persona que llama.

Step 2 - rechazar (Error ("Negativos no admitidos"));

La implementación del método se da en el siguiente código (PASO 1).

function getSum(n1, n2) {   
   varisAnyNegative = function() {   
      return n1 < 0 || n2 < 0;   
   }   
   var promise = new Promise(function(resolve, reject) {   
      if (isAnyNegative()) {   
         reject(Error("Negatives not supported"));   
      }   
      resolve(n1 + n2)
   });   
   return promise;   
}

El segundo paso detalla la implementación de la persona que llama (PASO 2).

La persona que llama debe usar el método 'entonces', que toma dos métodos de devolución de llamada: primero para el éxito y segundo para el fracaso. Cada método toma un parámetro, como se muestra en el siguiente código.

getSum(5, 6)   
.then(function (result) {   
   console.log(result);   
},   
function (error) {   
   console.log(error);   
});

La siguiente salida se muestra en la ejecución exitosa del código anterior.

11

Dado que el tipo de retorno de getSum () es una Promise, en realidad podemos tener múltiples declaraciones 'then'. El primer 'entonces' tendrá una declaración de retorno.

getSum(5, 6)   
.then(function(result) {   
   console.log(result);   
   returngetSum(10, 20); 
   // this returns another promise   
},   
function(error) {   
   console.log(error);   
})   
.then(function(result) {   
   console.log(result);   
}, 
function(error) {   
   console.log(error);
});

La siguiente salida se muestra en la ejecución exitosa del código anterior.

11
30

El siguiente ejemplo emite tres llamadas then () con el método getSum ().

<script>   
   function getSum(n1, n2) {   
      varisAnyNegative = function() {   
         return n1 < 0 || n2 < 0;   
      }   
      var promise = new Promise(function(resolve, reject) {   
         if (isAnyNegative()) {   
            reject(Error("Negatives not supported"));   
         }   
         resolve(n1 + n2);   
      });   
      return promise;   
   }   
   getSum(5, 6)   
   .then(function(result) {   
      console.log(result);   
      returngetSum(10, 20); 
      //this returns another Promise   
   },   
   function(error) {   
      console.log(error);   
   })
   .then(function(result) {   
      console.log(result);   
      returngetSum(30, 40); 
      //this returns another Promise   
   }, 
   function(error) {   
      console.log(error);   
   })   
   .then(function(result) {   
      console.log(result);   
   }, 
   function(error) {         
      console.log(error);   
   });   
   console.log("End of script ");   
</script>

La siguiente salida se muestra en la ejecución exitosa del código anterior.

El programa muestra primero el 'final del script' y luego los resultados de llamar al método getSum (), uno por uno.

End of script  
11 
30 
70

Esto muestra que se llama a getSum () en estilo asincrónico o sin bloqueo. Promise ofrece una forma agradable y limpia de lidiar con las devoluciones de llamada.