AngularJS:凡使用的承诺? [英] AngularJS : Where to use promises?

查看:103
本文介绍了AngularJS:凡使用的承诺?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看到用的承诺访问FB图形API

I saw some examples of Facebook Login services that were using promises to access FB Graph API

示例1

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;
}

和所使用的服务$范围。$摘要()// Manualy范围评估时,得到的回应

And services that used "$scope.$digest() // Manualy scope evaluation" when got the response

示例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

的问题是:


  • 什么区别在上面的例子?

  • 什么原因案例使用的 $ Q 的服务?

  • ,它是如何的工作

  • what the difference in examples above?
  • what the reasons and cases to use $q service?
  • and how does it work?

推荐答案

这不会是一个完整的回答你的问题,但希望这将帮助您和他人当您尝试阅读的<$ c中的文档$ C> $ q 服务。我花了一段时间来理解它。

This is not going to be a complete answer to your question, but hopefully this will help you and others when you try to read the documentation on the $q service. It took me a while to understand it.

让我们留出片刻AngularJS,只是考虑Facebook的API调用。这两个API调用使用的回调的机制来通知来电时,从Facebook的响应可用:

Let's set aside AngularJS for a moment and just consider the Facebook API calls. Both the API calls use a callback mechanism to notify the caller when the response from Facebook is available:

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

这是对JavaScript和其他语言处理异步操作的标准模式。

This is a standard pattern for handling asynchronous operations in JavaScript and other languages.

当您需要执行异步操作,每个操作连续依赖于previous操作的结果的顺序对这种模式的一个大问题就出现了。这就是这个code做:

One big problem with this pattern arises when you need to perform a sequence of asynchronous operations, where each successive operation depends on the result of the previous operation. That's what this code is doing:

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

首先,它只是验证登录成功它发出请求到图形API之后尝试登录,然后。

First it tries to log in, and then only after verifying that the login was successful does it make the request to the Graph API.

即使在这种情况下,这是唯一的两个操作链接在一起,事情开始变得凌乱。该方法 askFacebookForAuthentication 接受失败和成功的回调,但是当 FB.login 成功,但会发生什么 FB.api 不成?此方法总是调用成功回调无论 FB.api 方法的结果。

Even in this case, which is only chaining together two operations, things start to get messy. The method askFacebookForAuthentication accepts a callback for failure and success, but what happens when FB.login succeeds but FB.api fails? This method always invokes the success callback regardless of the result of the FB.api method.

现在想象一下你正在试图code三个或更多的异步操作的一个强大的序列,在每个步骤中正确处理错误的方式,将是清晰给其他任何人,甚至给你几个星期后。有可能,但它很容易只保留那些筑巢回调和沿途失去跟踪的错误。

Now imagine that you're trying to code a robust sequence of three or more asynchronous operations, in a way that properly handles errors at each step and will be legible to anyone else or even to you after a few weeks. Possible, but it's very easy to just keep nesting those callbacks and lose track of errors along the way.

现在,让我们抛开Facebook的API了片刻,只考虑角承诺API,由 $ Q 服务来实现。该服务实现的模式是企图把异步编程回类似的东西线性一系列简单的语句,用在任何一步的能力,'扔'的错误,并在最后处理一下,语义相似熟悉的try / catch 块。

Now, let's set aside the Facebook API for a moment and just consider the Angular Promises API, as implemented by the $q service. The pattern implemented by this service is an attempt to turn asynchronous programming back into something resembling a linear series of simple statements, with the ability to 'throw' an error at any step of the way and handle it at the end, semantically similar to the familiar try/catch block.

考虑这个人为的例子。说,我们有两个功能,其中第二功能消耗了第一个的结果是:

Consider this contrived example. Say we have two functions, where the second function consumes the result of the first one:

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

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

 secondFn(firstFn()); 

现在想象firstFn和secondFn都需要很长的时间才能完成,所以我们要异步处理这个序列。首先,我们创建一个新的延迟对象,从而重新presents业务链:

Now imagine that firstFn and secondFn both take a long time to complete, so we want to process this sequence asynchronously. First we create a new deferred object, which represents a chain of operations:

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

产权重组presents链的最终结果。如果您在创建后立即登录一个承诺,你会看到,它仅仅是一个空对象( {} )。没什么可看的是,沿着右侧移动。

The promise property represents the eventual result of the chain. If you log a promise immediately after creating it, you'll see that it is just an empty object ({}). Nothing to see yet, move right along.

到目前为止,我们只能重新presents链起点的承诺。现在,让我们添加两个操作:

So far our promise only represents the starting point in the chain. Now let's add our two operations:

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

然后方法添加一个步骤链,然后返回一个新的承诺,重新presenting延伸链的最终结果。您可以根据需要添加尽可能多的步骤。

The then method adds a step to the chain and then returns a new promise representing the eventual result of the extended chain. You can add as many steps as you like.

到目前为止,我们已经建立了我们的功能链,但没有实际发生的情况。你得到的东西通过调用启动 deferred.resolve ,指定要传递给链中的第一个实际步骤初始值:

So far, we have set up our chain of functions, but nothing has actually happened. You get things started by calling deferred.resolve, specifying the initial value you want to pass to the first actual step in the chain:

 deferred.resolve('initial value');

然后......还是没有任何反应。为了确保模型的变化适当地观察,角实际上不调用链中的第一步,直到下一次 $适用正所谓:

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

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

所以有关错误处理的呢?到目前为止,我们只指定的成功处理程序的在供应链的每一步。 然后也接受了错误处理程序作为一个可选的第二个参数。下面是另一个,一个承诺链长的例子,这一次错误处理:

So what about error handling? So far we have only specified a success handler at each step in the chain. then also accepts an error handler as an optional second argument. Here's another, longer example of a promise chain, this time with error handling:

 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);

正如你可以看到在这个例子,链中的每个处理器都有机会疏导交通下的错误的处理程序,而不是在未来的成功的处理程序。在大多数情况下,你可以在链末端的单个错误处理,但你也可以有一个尝试恢复中间错误处理。

As you can see in this example, each handler in the chain has the opportunity to divert traffic to the next error handler instead of the next success handler. In most cases you can have a single error handler at the end of the chain, but you can also have intermediate error handlers that attempt recovery.

要快速返回到你的例子(和你的问题),我只想说,他们重新present两种不同的方式给Facebook的面向回调的API适应观察模型的变化角的方式。第一示例包装在一个承诺,其可被添加到一个范围,并且由角的模板系统理解的API调用。第二个需要直接设置回调结果的范围,然后调用 $范围的更强力的办法。$摘要()使角知道从变化外部源。

To quickly return to your examples (and your questions), I'll just say that they represent two different ways to adapt Facebook's callback-oriented API to Angular's way of observing model changes. The first example wraps the API call in a promise, which can be added to a scope and is understood by Angular's templating system. The second takes the more brute-force approach of setting the callback result directly on the scope, and then calling $scope.$digest() to make Angular aware of the change from an external source.

的两个例子是不能直接比较,因为第一缺少的登录步骤。然而,这是通常希望封装与外部的API类似这样的独立服务的交互,以及结果的承诺提供给控制器。你可以保持你的控制器通过这种方式从外部的关注分开,并与模拟服务更轻松地对其进行测试。

The two examples are not directly comparable, because the first is missing the login step. However, it's generally desirable to encapsulate interactions with external APIs like this in separate services, and deliver the results to controllers as promises. That way you can keep your controllers separate from external concerns, and test them more easily with mock services.

这篇关于AngularJS:凡使用的承诺?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆