我正在使用Angular 1.5.8。我的应用中的视图需要相同3个AJAX请求的不同组合。有些视图需要所有这三个视图,而另一些则需要两个数据,甚至需要一个来自两个端点的数据。
我正在研究一个可以管理此数据检索的函数,要求该应用仅调用每个端点一次。我希望AJAX请求根据需要称为,但仅在需要时。目前,我已经创建了一个有效的函数,但似乎可以使用改进。
以下功能包含在$rootScope
中。它使用fetchData()
函数根据要求循环通过GET请求。检索数据后,将其存储在全局变量$ rootscope.appdata中,然后再次调用fetchData()
。当检索所有数据时,已解决递延的承诺并将数据返回到控制器。
$rootScope.appData = {};
$rootScope.loadAppData = function(fetch) {
var deferred = $q.defer();
function getUser() {
$http
.get('https://example.com/api/getUser')
.success(function(result){
$rootScope.appData.currentUser = result;
fetchData();
});
}
function getPricing() {
$http
.get('https://example.com/api/getPricing')
.success(function(result) {
$rootScope.appData.pricing = result;
fetchData();
});
}
function getBilling() {
$http
.get('https://example.com/api/getBilling')
.success(function(result) {
$rootScope.appData.billing = result;
fetchData();
});
}
function fetchData() {
if (fetch.user && !$rootScope.appData.currentUser) {
getUser();
} else if (fetch.pricing && !$rootScope.appData.pricing) {
getPricing();
} else if (fetch.billing && !$rootScope.appData.billing) {
getBilling();
} else {
deferred.resolve($rootScope.appData);
}
}
if ($rootScope.appData.currentUser && $rootScope.appData.pricing &&$rootScope.appData.billing) {
deferred.resolve($rootScope.appData);
} else {
fetchData();
}
return deferred.promise;
};
将对象fetch
作为属性提交,此对象显示AJAX请求调用的对象。一个示例调用$rootScope.loadAppData()
,其中仅 user 和定价 data的示例会如下所示:
$rootScope.loadAppData({user: true, pricing: true}).then(function(data){
//execute view logic.
});
我想知道:
- 是否应该以不同的方式完成这些功能?
fetchData()
功能足够,还是这是执行此功能的奇怪方法? - 是否有一种方法可以同时致电AJAX请求,但是请等待所有必需的电话完成,然后再解决承诺?
- 将这样的数据存储在
$rootScope
中是不寻常的吗?
我知道此功能目前尚未正确处理错误。这是我在使用此片段之前要添加的功能,但与我的问题无关。
而不是使用.success
方法,而是使用.then
方法和返回数据到其成功处理程序:
function getUserPromise() {
var promise = $http
.get('https://example.com/api/getUser')
.then( function successHandler(result) {
//return data for chaining
return result.data;
});
return promise;
}
使用服务代替$ Rootscope:
app.service("myService", function($q, $http) {
this.loadAppData = function(fetchOptions) {
//Create first promise
var promise = $q.when({});
//Chain from promise
var p2 = promise.then(function(appData) {
if (!fetchOptions.user) {
return appData;
} else {
var derivedPromise = getUserPromise()
.then(function(user) {
appData.user = user;
//return data for chaining
return appData;
});
return derivedPromise;
);
});
//chain from p2
var p3 = p2.then(function(appData) {
if (!fetchOptions.pricing) {
return appData;
} else {
var derivedPromise = getPricingPromise()
.then(function(pricing) {
appData.pricing = pricing;
//return data for chaining
return appData;
});
return derivedPromise;
);
});
//chain from p3
var p4 = p3.then(function(appData) {
if (!fetchOptions.billing) {
return appData;
} else {
var derivedPromise = getBillingPromise()
.then(function(user) {
appData.billing = billing;
//return data for chaining
return appData;
});
return derivedPromise;
);
});
//return final promise
return p4;
}
});
上面的示例为空对象创造了承诺。然后它将三个操作链。每个操作都检查是否需要提取。如果需要,则执行提取,并将结果附加到appData
对象;如果不需要提取,则appData
对象将传递到链中的下一个操作。
用法:
myService.loadAppData({user: true, pricing: true})
.then(function(appData){
//execute view logic.
}).catch(functon rejectHandler(errorResponse) {
console.log(errorResponse);
throw errorResponse;
});
如果任何提取操作都失败了,则将跳过链中的后续操作,最终拒绝处理程序将被调用。
因为调用诺言的 在原始帖子中找到了一种回答问题2 的好方法。使用.then
方法会返回一个新的派生承诺,所以很容易创建一条诺言。可以创建任何长度的链条,并且可以通过另一个承诺解决承诺(这将进一步推迟其决议),因此可以在链中的任何时候暂停诺言的解决方案。这使得实现功能强大的API。$q.all()
允许承诺同时执行,一旦完成后就可以解决,或者一旦其中一个失败就会失败。@georgeawg,我已经将此逻辑添加到了服务中。这是我的重写,将此代码放入服务中,并同时运行所有调用: services.factory('appData', function($http, $q) {
var appData = {};
var coreData = {};
appData.loadAppData = function(fetch) {
var deferred = $q.defer();
var getUser = $q.defer();
var getPricing = $q.defer();
var getBilling = $q.defer();
if (!fetch.user || coreData.currentUser) {
getUser.resolve();
} else {
$http
.get('https://example.com/api/getUser')
.success(function(result){
coreData.currentUser = result;
getUser.resolve();
}).error(function(reason) {
getUser.reject(reason);
});
}
if (!fetch.billing || coreData.billing) {
getBilling.resolve();
} else {
$http
.get('https://example.com/api/getBilling')
.success(function(result) {
coreData.billing = result;
getBilling.resolve();
}).error(function(reason) {
getBilling.reject(reason);
});
}
if (!fetch.pricing || coreData.pricing) {
getPricing.resolve();
} else {
$http
.get('https://example.com/api/getPricing')
.success(function(result) {
coreData.pricing = result;
getPricing.resolve();
}).error(function(reason) {
getPricing.reject(reason);
});
}
$q.all([getPricing.promise, getUser.promise, getBilling.promise]).then(function(result) {
deferred.resolve(coreData);
}, function(reason){
deferred.reject(reason);
});
return deferred.promise;
};
return appData;
});