我有一个角度问题,即使我使用$ q.defer功能,结果会在实际完成之前返回到我的控制器。我的服务中有以下功能
getFileInfo : function (fulfillmentId)
{
var pdfResults = [];
var jpgResults = [];
var orderDetails = {};
var deferred = $q.defer();
$http.get(appConstants.api_url + '/references/' + fulfillmentId + '/files?max=2000')
. then (function (fileResults)
{
angular.forEach(fileResults.data.entities,function(value)
{
if(value.file.extension == 'pdf')
{
pdfResults.push({files : value});
}
if(value.file.extension == 'jpg')
{
jpgResults.push({files : value});
}
});
orderDetails.jpgResults = jpgResults;
return pdfResults;
})
.then (function (pdfResults)
{
angular.forEach(pdfResults,function(value,key)
{
var fileUuid = value.files.file.file_uuid;
return $http.get(appConstants.api_url + '/resources/' + fileUuid + '/tags')
.then (function (preflightResults)
{
var deserializeJson = [];
deserializeJson.push(angular.fromJson(preflightResults.data.entities[0].resource_json));
var formatedPreflightResults = localAPI.addUIMessages(deserializeJson);
pdfResults[key].preflightResults = formatedPreflightResults;
});
});
orderDetails.pdfResults = pdfResults;
deferred.resolve(orderDetails);
});
return deferred.promise;
}
我从我的控制器调用它就像这样:
conformAPI.getFileInfo($scope.fulfillmentId)
.then (function (results)
{
console.log(results);
console.log(results.pdfResults[0]);
console.log(results.pdfResults[0].preflightResults)
});
我遇到的问题是我正在做的最后一个控制台日志是未定义的。其他一切都很好地回归结果。第一个和第二个控制台就像那里有preflightResults对象,但它似乎有点迟了。我想通过使用$ q.defer,在一切都完成之前不会返回任何内容。关于如何解决这个问题的任何想法?
答案 0 :(得分:1)
看起来你不是在等待“getFile”获取请求的结果。 我稍微重构了你的代码。它可能不起作用,因为我无法运行它,但你应该看到我的观点。
getFileInfo: function (fulfillmentId) {
var pdfResults = [];
var jpgResults = [];
var orderDetails = {};
var deferred = $q.defer();
function getByFileId(fileUuid, preflightResults) {
return $http.get(appConstants.api_url + '/resources/' + fileUuid + '/tags')
.then(function (preflightResults) {
var deserializeJson = [];
deserializeJson.push(angular.fromJson(preflightResults.data.entities[0].resource_json));
var formatedPreflightResults = localAPI.addUIMessages(deserializeJson);
return formatedPreflightResults;
});
}
function getFiles(pdfResults) {
var subDefer = $q.defer();
var current = 0;
angular.forEach(pdfResults, function (value, key) {
current += 1;
var fileUuid = value.files.file.file_uuid;
getByFileUuid(fileUuid, preflightResults)
.then(function (results) {
pdfResults[key].preflightResults = results;
// need to know when done with all
if (pdfResults.length === current) {
subDefer.resolve(pdfResults);
}
});
});
return subDefer.promise;
}
$http.get(appConstants.api_url + '/references/' + fulfillmentId + '/files?max=2000')
.then(function (fileResults) {
angular.forEach(fileResults.data.entities, function (value) {
if (value.file.extension == 'pdf') {
pdfResults.push({ files: value });
}
if (value.file.extension == 'jpg') {
jpgResults.push({ files: value });
}
});
orderDetails.jpgResults = jpgResults;
return pdfResults;
}).then(getFiles).then(function(pdfResults) {
orderDetails.pdfResults = pdfResults;
deferred.resolve(orderDetails);
});
return deferred.promise;
}
答案 1 :(得分:0)
你太早解决了你的承诺。
因为你的第一个然后()只返回一个对象,所以第二个然后()将立即跟随。所以这就是代码正在做的事情(粗糙的伪代码):
$ http.get()。然后(首先返回$ http.get);
一旦您开始获取第一个文件,就会返回(return $http.get(appConstants.api_url +
...)。此时,只有顶部的第一个$ http.get肯定已经解决了。您可能会看到第二个$ http.get(第一个文件)很快就会解决,但您还没有再启动任何更多文件的$ http.gets。
您可能在此代码中的目标是,如果删除中间返回以便生成所有$ http.gets,则为:
$ http.get()。然后(启动所有$ http.gets并解决promise);
只要您循环浏览所有文件并使用$ http.get启动它们,就可以解决承诺。这有同样的问题 - 承诺得到解决太早。所有的收益都已发出,但你无法确定它们是否已经回来了。
你能做的是:
$ http.get()。然后(启动所有$ http.gets并在完成所有操作后解决承诺);
例如,代替pdfResults上的forEach,您可以将它们映射到$ http.get的数组:filePromises = pdfResults.map(function(e)$ http.get(e))
然后你会在你现在有deferred.resolve(orderDetails)的末尾return $q.all(filePromises)
。