141 votes

Promesses en AngularJS et où les utiliser ?

J'ai vu quelques exemples de Facebook Login services qui ont été à l'aide de promesses pour accéder à FB API Graphique

Exemple #1 exemple:

this.api = function(item) {
  var deferred = $q.defer();
  if (item) {
    facebook.FB.api('/' + item, function (result) {
      $rootScope.$apply(function () {
        if (angular.isUndefined(result.error)) {
          deferred.resolve(result);
        } else {
          deferred.reject(result.error);
        }
      });
    });
  }
  return deferred.promise;
}

Et services utilisés "$scope.$digest() // Manualy scope evaluation" quand eu la réponse

Exemple #2:

angular.module('HomePageModule', []).factory('facebookConnect', function() {
    return new function() {
        this.askFacebookForAuthentication = function(fail, success) {
            FB.login(function(response) {
                if (response.authResponse) {
                    FB.api('/me', success);
                } else {
                    fail('User cancelled login or did not fully authorize.');
                }
            });
        }
    }
});

function ConnectCtrl(facebookConnect, $scope, $resource) {

    $scope.user = {}
    $scope.error = null;

    $scope.registerWithFacebook = function() {
        facebookConnect.askFacebookForAuthentication(
        function(reason) { // fail
            $scope.error = reason;
        }, function(user) { // success
            $scope.user = user
            $scope.$digest() // Manual scope evaluation
        });
    }
}

JSFiddle

Les questions sont:

  • ce que la différence dans les exemples ci-dessus?
  • ce que les raisons et les cas d'utilisation $q service?
  • et comment faut-il travailler?

P. S. ce ne sont pas mes propres exemples, de sorte que votre vision de façons correctes de mise en œuvre sont également appréciés. P. P. S. s'il vous Plaît, ne réagissent pas comme "le lien % - RTFM!", J'espère que vos réponses ne sont pas seulement pour moi. =)

Merci!

401voto

karlgold Points 3636

Ce n'est pas une réponse complète à votre question, mais j'espère que cela va vous aider, vous et d'autres personnes lorsque vous essayez de lire la documentation sur l' $q de service. Il m'a fallu un certain temps pour le comprendre.

Laissons de côté AngularJS pour un moment, et il suffit de considérer le Facebook des appels d'API. À la fois les appels d'API utiliser un rappel de mécanisme pour informer l'appelant lorsque la réponse de Facebook est disponible:

  facebook.FB.api('/' + item, function (result) {
    if (result.error) {
      // handle error
    } else {
      // handle success
    }
  });
  // program continues while request is pending
  ...

C'est un modèle standard pour la manipulation des opérations asynchrones en JavaScript et d'autres langages.

Un gros problème avec ce modèle se pose lorsque vous avez besoin pour effectuer une séquence d'opérations asynchrones, où chaque opération dépend du résultat de l'opération précédente. C'est ce que ce code est en train de faire:

  FB.login(function(response) {
      if (response.authResponse) {
          FB.api('/me', success);
      } else {
          fail('User cancelled login or did not fully authorize.');
      }
  });

D'abord, il essaie de se connecter, puis seulement après avoir vérifié que la connexion a réussi t-il en faire la demande à l'API Graphique.

Même dans ce cas, qui est le seul à enchaîner deux opérations, les choses commencent à déraper. La méthode askFacebookForAuthentication accepte un rappel de l'échec et de la réussite, mais ce qui arrive quand FB.login réussit, mais FB.api d'échec? Cette méthode appelle toujours l' success rappel quel que soit le résultat de l' FB.api méthode.

Maintenant, imaginez que vous êtes en train de coder un robuste séquence de trois ou plus des opérations asynchrones, d'une manière qui gère correctement les erreurs à chaque étape et sera lisible pour quelqu'un d'autre ou même après quelques semaines. Possible, mais il est très facile de simplement continuer à la nidification de ces rappels et de perdre la trace des erreurs le long du chemin.

Maintenant, laissons de côté l'Facebook API, pour un moment, et il suffit de considérer l'angle de Promesses API, mis en oeuvre par l' $q de service. Le modèle mis en œuvre par ce service est une tentative de tourner la programmation asynchrone en arrière en quelque chose ressemblant à une série linéaire de déclarations simples, avec la possibilité de lancer une erreur à n'importe quelle étape de la voie et de le traiter à la fin, sémantiquement similaires aux familiers try/catch bloc.

Considérons cet exemple artificiel. Disons que nous avons deux fonctions, d'où la deuxième fonction qui consomme le résultat de la première:

 var firstFn = function(param) {
    // do something with param
    return 'firstResult';
 };

 var secondFn = function(param) {
    // do something with param
    return 'secondResult';
 };

 secondFn(firstFn()); 

Maintenant, imaginez que firstFn et secondFn ont tous deux une longue période de temps, si l'on veut traiter cette séquence de façon asynchrone. Nous avons d'abord créer un nouveau deferred de l'objet, ce qui représente une chaîne d'opérations:

 var deferred = $q.defer();
 var promise = deferred.promise;

L' promise propriété représente le résultat final de la chaîne. Si vous vous connectez une promesse immédiatement après la création, vous allez voir que c'est juste un objet vide ({}). Rien à voir pourtant, aller à droite le long.

Jusqu'à présent notre promesse ne représente que le point de départ de la chaîne. Maintenant, nous allons ajouter nos deux opérations:

 promise = promise.then(firstFn).then(secondFn);

L' then méthode ajoute une étape à la chaîne et renvoie une nouvelle promesse représentant le résultat final de l'extension de la chaîne. Vous pouvez ajouter autant d'étapes que vous le souhaitez.

Jusqu'à présent, nous avons mis en place notre chaîne de fonctions, mais rien de ce qui s'est réellement passé. Vous obtenez les choses ont commencé en appelant deferred.resolve, en spécifiant la valeur initiale que vous souhaitez passer à la première étape dans la chaîne:

 deferred.resolve('initial value');

Et puis...toujours rien ne se passe. Pour s'assurer que les changements de modèle sont bien suivies, Angulaire n'a pas fait appel de la première étape de la chaîne jusqu'à la prochaine fois $apply s'appelle:

 deferred.resolve('initial value');
 $rootScope.$apply();

 // or     
 $rootScope.$apply(function() {
    deferred.resolve('initial value');
 });

Alors, erreur de manipulation? Jusqu'à présent, nous avons seulement indiqué un gestionnaire de succès à chaque étape de la chaîne. then accepte également un gestionnaire d'erreur, comme un deuxième argument optionnel. En voici un autre, plus l'exemple d'une promesse de la chaîne, cette fois avec la gestion des erreurs:

 var firstFn = function(param) {
    // do something with param
    if (param == 'bad value') {
      return $q.reject('invalid value');
    } else {
      return 'firstResult';
    }
 };

 var secondFn = function(param) {
    // do something with param
    if (param == 'bad value') {
      return $q.reject('invalid value');
    } else {
      return 'secondResult';
    }
 };

 var thirdFn = function(param) {
    // do something with param
    return 'thirdResult';
 };

 var errorFn = function(message) {
   // handle error
 };

 var deferred = $q.defer();
 var promise = deferred.promise.then(firstFn).then(secondFn).then(thirdFn, errorFn);

Comme vous pouvez le voir dans cet exemple, chaque gestionnaire de la chaîne a l'occasion de détourner le trafic vers la prochaine erreur de gestionnaire au lieu de la prochaine succès gestionnaire. Dans la plupart des cas, vous pouvez avoir un seul gestionnaire d'erreur à la fin de la chaîne, mais vous pouvez aussi avoir l'intermédiaire des gestionnaires d'erreur que la tentative de récupération.

Pour revenir rapidement à vos exemples et vos questions), je vais juste dire qu'elles représentent deux manières différentes pour s'adapter Facebook callback de l'API orientée Angulaire de la voie de l'observation des changements de modèle. Le premier exemple encapsule l'appel d'API en une promesse, qui peut être ajouté à un champ d'application et est entendu par Angulaire du système de template. Le second prend le plus de force brute approche de définition de la fonction de rappel directement le résultat sur le champ, puis en appelant $scope.$digest() faire Angulaire au courant du changement à partir d'une source externe.

Les deux exemples qui ne sont pas directement comparables, car la première est manquant, l'étape de connexion. Cependant, il est généralement souhaitable d'encapsuler les interactions avec les Api externe de ce genre dans des services distincts, et d'envoyer les résultats aux contrôleurs que des promesses. De cette façon, vous pouvez garder vos contrôleurs séparés de préoccupations externes, et de les tester plus facilement avec des simulations de services.

9voto

Michal Stefanow Points 1223

Je m'attendais à une réponse complexe qui permettra de couvrir à la fois: pourquoi ils sont utilisés dans général et comment l'utiliser dans Angulaire

C'est le plunk pour angulaires promesses MVP (minimum viable promesse): http://plnkr.co/edit/QBAB0usWXc96TnxqKhuA?p=preview

Source:

(pour ceux qui ont la flemme de cliquer sur les liens)

index.html

  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.js"></script>
    <script src="app.js"></script>
  </head>

  <body ng-app="myModule" ng-controller="HelloCtrl">
    <h1>Messages</h1>
    <ul>
      <li ng-repeat="message in messages">{{ message }}</li>
    </ul>
  </body>

</html>

app.js

angular.module('myModule', [])

  .factory('HelloWorld', function($q, $timeout) {

    var getMessages = function() {
      var deferred = $q.defer();

      $timeout(function() {
        deferred.resolve(['Hello', 'world']);
      }, 2000);

      return deferred.promise;
    };

    return {
      getMessages: getMessages
    };

  })

  .controller('HelloCtrl', function($scope, HelloWorld) {

    $scope.messages = HelloWorld.getMessages();

  });

(Je sais qu'il ne faut pas résoudre vos Facebook exemple mais je trouve les extraits suivants utile)

Via: http://markdalgleish.com/2013/06/using-promises-in-angularjs-views/


Mise à jour le 28 Février 2014: Que de 1.2.0, les promesses ne sont plus résolu par des modèles. http://www.benlesh.com/2013/02/angularjs-creating-service-with-http.html

(plunker exemple utilise 1.1.5.)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X