AngularJS:在哪里使用承诺?
我看到了一些Facebook登录服务的例子,它们使用承诺访问FB Graph APIAngularJS:在哪里使用承诺?,angularjs,deferred,promise,Angularjs,Deferred,Promise,我看到了一些Facebook登录服务的例子,它们使用承诺访问FB Graph API <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="myMo
<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>
示例#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;
}
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
});
}
}
<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>
以及在收到响应时使用“$scope.$digest()//手动范围评估”
的服务
<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>
示例2:
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;
}
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
});
}
}
<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>
<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>
问题是:
<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>
- 上述示例中的差异是什么李>
- 使用$q服务的原因和案例是什么
- 它是如何工作的
- 这并不是对您问题的完整回答,但希望这能帮助您和其他人阅读
服务的文档。我花了一段时间才明白$q
让我们暂时搁置AngularJS,只考虑脸谱网API调用。这两个API调用都使用回调机制在Facebook的响应可用时通知调用方:<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>
facebook.FB.api('/' + item, function (result) { if (result.error) { // handle error } else { // handle success } }); // program continues while request is pending ...
这是用JavaScript和其他语言处理异步操作的标准模式<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>
当您需要执行一系列异步操作时,这种模式会出现一个大问题,其中每个后续操作都取决于前一个操作的结果。这就是这段代码所做的:<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>
FB.login(function(response) { if (response.authResponse) { FB.api('/me', success); } else { fail('User cancelled login or did not fully authorize.'); } });
首先,它尝试登录,然后只有在验证登录成功后,它才会向Graph API发出请求<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>
即使在这种情况下,仅仅是将两个操作链接在一起,事情也开始变得一团糟。方法<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>
接受失败和成功的回调,但是当askFacebookForAuthentication
成功但FB.login
失败时会发生什么?无论FB.api
方法的结果如何,此方法始终调用FB.api
回调success
现在想象一下,您正试图编写一个由三个或更多异步操作组成的健壮序列,以一种在每一步都能正确处理错误的方式,并且在几周后,其他任何人甚至您都能清楚地看到。有可能,但是很容易将这些回调嵌套起来,并在过程中丢失错误跟踪<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>
<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>
现在,让我们暂时搁置脸谱网API,只考虑角代码API,由<代码> $q/COD>服务实现。该服务实现的模式是尝试将异步编程转换回类似于一系列简单语句的线性序列,能够在任何一步“抛出”错误,并在最后进行处理,语义类似于熟悉的
块try/catch
考虑这个人为的例子。假设我们有两个函数,其中第二个函数消耗第一个函数的结果:<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>
var firstFn = function(param) { // do something with param return 'firstResult'; }; var secondFn = function(param) { // do something with param return 'secondResult'; }; secondFn(firstFn());
现在假设firstFn和secondFn都需要很长时间才能完成,所以我们希望异步处理这个序列。首先,我们创建一个新的<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>
对象,它表示一系列操作:deferred
var deferred = $q.defer(); var promise = deferred.promise;
promise = promise.then(firstFn).then(secondFn);
<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>
属性表示链的最终结果。如果在创建承诺后立即将其记录下来,您将看到它只是一个空对象(promise
)。还没什么可看的,走吧{}
到目前为止,我们的承诺只代表了这一链条的起点。现在,让我们添加两个操作:<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>
var deferred = $q.defer(); var promise = deferred.promise;
promise = promise.then(firstFn).then(secondFn);
<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>
方法向链添加一个步骤,然后返回一个表示扩展链最终结果的新承诺。您可以添加任意数量的步骤then
到目前为止,我们已经建立了我们的功能链,但实际上什么都没有发生。通过调用<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>
,指定要传递到链中第一个实际步骤的初始值,可以开始操作:deferred.resolve
deferred.resolve('initial value');
然后…还是什么都没发生。为确保正确观察模型更改,Angular在下次调用<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>
之前不会实际调用链中的第一步:$apply
deferred.resolve('initial value'); $rootScope.$apply(); // or $rootScope.$apply(function() { deferred.resolve('initial value'); });
那么错误处理呢?到目前为止,我们只在链中的每个步骤指定了一个成功处理程序<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>
还接受错误处理程序作为可选的第二个参数。下面是另一个较长的承诺链示例,这次是错误处理:然后
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);
如本例所示,链中的每个处理程序都有机会将流量转移到下一个错误处理程序,而不是下一个成功处理程序。在大多数情况下,在链的末尾可以有一个错误处理程序,但也可以有尝试恢复的中间错误处理程序<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>
为了快速返回到您的示例(以及您的问题),我只想说,它们代表了两种不同的方式,使Facebook面向回调的API适应Angular观察模型更改的方式。第一个示例将API调用封装在一个promise中,该promise可以添加到一个作用域中,Angular的模板系统可以理解它。第二种方法采用更为暴力的方法,直接在作用域上设置回调结果,然后调用<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>
,以使Angle了解来自外部源的更改$scope.$digest()
这两个示例没有直接的可比性,因为第一个缺少登录步骤。然而,通常希望将与外部API的交互封装在单独的服务中,并将结果作为承诺交付给控制器。这样,您就可以将控制器与外部关注点分开,并使用模拟服务更轻松地测试它们<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>
我希望有一个复杂的答案能涵盖这两个方面:为什么它们会被用于 概述,以及如何使用它的角度<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>
这是角度承诺MVP的最低可行承诺:<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>
资料来源: (对于那些懒得点击链接的人)<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>
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>
(我知道这并不能解决您的特定Facebook示例,但我发现以下代码片段很有用)<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>
通过:<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>
<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>
Upd