¡Esta es una revisión vieja del documento!


Justificación

Una “promesa” o también llamada “futuro” es un objeto que actúa como proxy en los casos en los que no se puede retornar el verdadero valor ya que aun no se conoce pero no se puede bloquear la función esperando a que llegue. Es una forma de hacer las cosas en vez de usar las funciones de callback.

Voy a volver a explicarlo pero con un ejemplo: Al hacer una llamada Ajax con $http, la llamada a $http no retorna ningún valor ya que aun no tiene dicho valor pero tampoco se puede bloquear esperando a que llegue. Pues realmente el servicio $http si que retorna un valor. Esto que retorna es una promesa y como hemos dicho la promesa es un proxy que en un futuro contendrá el valor.

Ahora que quizás entiendas la buena idea de las promesas, pasemos a la parte negativa. La promesa tendrá en un futuro el valor pero, ¿como nos enteramos que ahora la promesa ya tiene el valor? Pues usando una función de /callback. ¿Como?!!, Pero no habíamos dicho que lo bueno de las promesas es evitar las funciones de callback.

Pirámide de la muerte

Excepto en un caso que ya veremos mas adelante, realmente no podemos evitar las funciones de callback pero si que podemos evitar lo que se llama la pirámide de la muerte (en ingles Pyramid of Doom)). La pirámide de la muerte se produce cuando dentro de una función de callback hacemos otra llamada asíncrona que a su vez tiene otra función de callback y dentro de esta nueva función de callback hacemos otra llamada asíncrona, y así sucesivamente.

Podemos ver como queda la pirámide de la muerte en el siguiente ejemplo.

Obtenemos el fichero json “fichero1.json” y leemos el valor de “importe” pero dentro volvemos a obtener el fichero “fichero2.json” y obtenemos el valor del importe que sumamos al primer importe, …..y así hasta 4 veces.

    $scope.importeTotal = 0;
    $scope.mensajeFinal = "";
    
    $http({method: 'GET',url: 'fichero1.json'}).success(function(data, status, headers, config) {
      $scope.importeTotal = $scope.importeTotal + data.importe;
      $http({method: 'GET',url: 'fichero2.json'}).success(function(data, status, headers, config) {
        $scope.importeTotal = $scope.importeTotal + data.importe;
        $http({method: 'GET',url: 'fichero3.json'}).success(function(data, status, headers, config) {
          $scope.importeTotal = $scope.importeTotal + data.importe;
          $http({method: 'GET',url: 'fichero4.json'}).success(function(data, status, headers, config) {
            $scope.importeTotal = $scope.importeTotal + data.importe;
            $scope.mensajeFinal = "Ya hemos finalizado la lista de cálculos";
          });
        });
      });
    });

Hemos quitado las funciones de error para que se vea mejor el ejemplo.

Vemos como estamos añadiendo funciones dentro de funciones lo que crea que el código esté cada vez mas identado lo que crea una forma de pirámide y da nombre al problema.

El problema de esto es que el código es poco modular, cada una de las funciones de callback está dentro de la anterior, haciendo que separarlas sea complejo.

Veamos ahora el mismo ejemplo usando promesas

    $scope.importeTotalPromesas = 0;
    $scope.mensajeFinalPromesas="";
    
    $http({ method: 'GET',url: 'fichero1.json'}).then(function(resultado) {
      $scope.importeTotalPromesas = $scope.importeTotalPromesas + resultado.data.importe;
      return $http({method: 'GET',url: 'fichero2.json'})
    }).then(function(resultado) {
      $scope.importeTotalPromesas = $scope.importeTotalPromesas + resultado.data.importe;
      return $http({method: 'GET',url: 'fichero3.json'})
    }).then(function(resultado) {
      $scope.importeTotalPromesas = $scope.importeTotalPromesas + resultado.data.importe;
      return $http({method: 'GET',url: 'fichero4.json'})
    }).then(function(resultado) {
      $scope.importeTotalPromesas = $scope.importeTotalPromesas + resultado.data.importe;
      $scope.mensajeFinalPromesas = "Ya hemos finalizado la lista de cálculos con promesas";
    })

Aunque aun no hemos explicado como funcionan las promesas vemos en este ejemplo que ahora no hay 4 funciones independiente y que no están anidadas por lo que es mas sencillo separarlas en funciones independiente.

Otras ventajas

Siempre que se habla de las promesas se explican que resuelven el problema de la pirámide de la muerte pero desde mi punto de vista tienen otras ventajas que las hacen también útiles:

API Unificado

En el entorno de JavaScript se produce mucho el fenómeno de llamadas asíncronas y el consiguiente uso de callbacks. Eso lleva a que tengamos de definir como son esos callbacks. Aunque puede parecer una tarea sencilla realmente hay muchas formas de hacer los callbacks, veamos algunos ejemplos.

Para poner las distintas formas , vamos a suponer lo siguiente.

  • Un método llamado “llamadaAsincrona” al que le pasamos un parámetro con el valor “EURO”
  • Si todo funciona correctamente , una función de callback con dos argumentos con los datos llamados ret1 y ret2
  • Si algo falla, una función de callback llamada errorCallback con dos argumentos de error llamados codError y mensajeError.

llamadaAsincrona("EURO",function (ret1,ret2) {
   alert(ret1 + "," + ret2);
},function(codError,mensajeError) {
   alert(codError + "," + mensajeError);
});
En la propia llamada se pasan las 2 funciones de callback

llamadaAsincrona("EURO").sucess(function (ret1,ret2) {
   alert(ret1 + "," + ret2);
}).error(function(codError,mensajeError) {
   alert(codError + "," + mensajeError);
});
Ahora la función llamadaAsincrona retorna un objeto que tiene los métodos sucess y error a los que le pasamos a cada uno la función correspondiente.

llamadaAsincrona("EURO").then(function (ret1,ret2) {
   alert(ret1 + "," + ret2);
},function(codError,mensajeError) {
   alert(codError + "," + mensajeError);
});

Ahora se retorna un objeto con un método then al que ahora se le pasan las 2 funciones.

llamadaAsincrona("EURO").then(function (data) {
   alert(data.ret1 + "," + data.ret2);
},function(error) {
   alert(error.codError + "," + error.mensajeError);
});
Este caso es como el anterior pero en vez de pasar 2 argumentos en las funciones de callback solo se pasa un solo objeto que tiene como propiedades los 2 valores.

Como vemos hay muchas formas de hacer las funciones de callback. Usando el API de promesas de AngularJS en nuestro código unificaremos la forma de trabajar de toda la aplicación.

Hay que decir que el servicio $http no es exactamente una promesa por lo que el propio AngularJS no ha pretendido tener un solo API. El motivo de ello supongo que habrá sido el facilitar el uso del servicio de $http pero personalmente creo que ha sido un error , yo hubiera obligado a usar siempre todo como promesas.

Resueltos antes de llamar al controlador

Lo que vamos a explicar ahora es para mi la mayor ventana de explicar las promesas y es el verdadero motivo por el que las explico ahora en vez de dejarlas como algo avanzado para el final.

Vemos visto en los controladores como hacemos llamadas a $http ( aunque sea a través de servicios )) para obtener los datos. Eso tiene un problema, La página ya se ha mostrado pero aun estamos esperando los datos. Lo ideal sería que si el controlador tuviera los datos que necesita antes de mostrarse la página y antes de ejecutarse el controlador. Gracias a las promesas y al servicio de rutas de AngularJS esto es posible.

No vamos ahora a contar el sistema de rutas ni como funciona, eso lo dejamos para la próxima unidad pero solo repetir que gracias a las promesas podemos tener datos que se obtienen de forma asíncrona pero que llegarán al controlador antes de que éste se ejecute. Por lo que será como si fuera algo síncrono.

Ejemplo

Referencias

unidades/06_promesas/01_justificacion.1408108783.txt.gz · Última modificación: 2014/08/15 15:19 por admin
Ir hasta arriba
CC Attribution-Share Alike 3.0 Unported
chimeric.de = chi`s home Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0