我有一个服务,它调用另外两个异步服务并返回一些组合数据,但是如何在 AngularJS 中做到这一点。
我有一个控制器,我想在其中调用这两个类似于这样的方法:
function ServiceC(serviceA,serviceB) {
var dataA = serviceA.GetAsyncStuff(); //returns promise
var dataB = serviceB.GetAsyncStuff(); //returns promise
return 'Greetings ' + dataA + dataB;
}
有没有比实际嵌套 Then 方法调用更聪明的方法,如下所示:
function ServiceC(serviceA,serviceB) {
var dataA = serviceA.GetAsyncStuff().then(function(respA){
var dataB = serviceB.GetAsyncStuff().then(function(respB){
return 'Greetings ' + respA.data + respB.data;
});
});
}
这个例子当然有点简化。
这是一个演示 plunker: http://plnkr.co/edit/yCrbwnarVDqwC4GBxhGg?p=preview
您需要使用$q.all
:
app.factory('myService', function($q, serviceA, serviceB, serviceC){
// $http returns a response object so we need to extract the data
var fn = function(res){
return res.data;
};
var promises = [
serviceA.GetAsyncStuff().then(fn),
serviceB.GetAsyncStuff().then(fn)
];
return $q.all(promises).then(function(data){
// you can manipulate consolidated data here
// data.push(serviceC);
return data;
});
});
从$q文档中:
$q#全部(承诺);
将多个承诺合并为一个承诺,当解析所有输入承诺时,将解析该承诺。
返回
返回将使用值数组/哈希解析的单个承诺,每个值对应于承诺数组/哈希中同一索引/键处的承诺。如果任何承诺通过拒绝解决,则此生成的承诺将以相同的拒绝值被拒绝。
function ServiceC(serviceA,serviceB) {
var _totalData = {};
var dataA = serviceA.GetAsyncStuff().then(function(respA){
_totalData = respA;
});
var dataB = serviceB.GetAsyncStuff().then(function(respB){
_totalData += respB;
});
return{ totalData: _totalData}
}
我说第一个更好,因为它有两个不同的调用,您可以添加数据并在最后返回它,在第二个示例中,您在服务下使用服务,这将产生节省一个服务价值的开销,直到第二个服务被调用并调用其数据, 你可以看到第二个网络压力是花费大量时间来获取资源和返回资源。
我们可以调用服务和返回承诺。
myApp.provider("myService", function($http,$q){
var serviceOneData = {},
serviceTwoData = {};
//call service 1
return {
serviceOneData : serviceOneData ,
serviceTwoData : serviceTwoData ,
getService1: function(){
var deferred = $q.defer();
$http({method: 'GET',url:'Service1',
headers:{
'Access-Control-Allow-Origin': '*'}}).
success(function(data,status,header,config){
serviceOneData = data;
deferred.resolve();
})
.error(function (data,status,header,config) {
deferred.reject();
});
//call service 2
return deferred.promise;
},
getService2: function(){
var Seconddeferred = $q.defer();
$http({method: 'GET',url:'Service2',
headers:{
'Access-Control-Allow-Origin': '*'}}).
success(function(data,status,header,config){
serviceTwoData = data;
Seconddeferred.resolve();
})
.error(function (data,status,header,config) {
Seconddeferred.reject();
});
//call service 2
return Seconddeferred.promise;
},
getService : getService1().then(getService2()).
then(
return serviceOneData + serviceTwoData
);
}
} );
你可以链接承诺:
angular.module('app',[])
.factory('Service1',function($q,$timeout){
return {
f: function(){
var deferred = $q.defer();
$timeout(function() {
deferred.resolve('Service 1');
},1000);
return deferred.promise;
}
}
})
.factory('Service2',function($q,$timeout,Service1){
return {
f: function(){
var deferred = $q.defer();
Service1.f().then(function(data){
$timeout(function() {
deferred.resolve('Service 2 '+ data);
},1000);
});
return deferred.promise;
}
}
})
.controller('MainCtrl', function($scope,Service2){
var promise2 = Service2.f();
promise2.then(function(data2){
console.log(data2);
});
});
或者只是使用
$q.all([Service1,Service2]).then
http://denisonluz.com/blog/index.php/2013/10/06/angularjs-returning-multiple-promises-at-once-with-q-all/
最好的办法是使用 $q.all
,这样可以确保在尝试执行函数之前已解析所有请求的承诺
function ServiceC(serviceA, serviceB, $q) {
var dataA = serviceA.GetAsyncStuff(); //returns promise
var dataB = serviceB.GetAsyncStuff(); //returns promise
$q.all([dataA, dataB]).then(doSomething);
}
编辑:如果您需要返回数据,则必须返回承诺。您可以只返回$q.all
,也可以在$q.all
解决后解决新承诺,例如
function ServiceC(serviceA, serviceB, $q) {
var dataA = serviceA.GetAsyncStuff(); //returns promise
var dataB = serviceB.GetAsyncStuff(); //returns promise
var deferred = $q.defer();
$q.all([dataA, dataB]).then(function (promises) {
deferred.resolve('Greetings ' + promises[0] + promises[1]);
});
return deferred.promise;
}