我正在构建一个离线项目,用户可以在其中进行游览(数据来自API)
每个巡视都有一定数量的部分,用户可以在地图上的某个点播放。此应用程序必须能够成为100%离线应用程序,因此当用户输入游览代码时,必须先从API检索数据,然后用户才能继续(因此应用程序会将游览的所有数据下线)。每个部分都有一个图像,视频和音频,可以在应用程序开始时下载。
问题是正在下载所有数据的函数调用是不同步的。 console.log指出该函数在下载所有数据之前已经结束。下面的代码:
function getAndFillFullTour() {
vm.showLoader = true;
// load data
TourFactory.getFullTour(vm.tourData.number, function(data){
if(data.state == 'success'){
vm.tourData = data;
var test = downloadData(function(){
// hide loader and continue tour
});
} else {
console.log('error');
}
});
}
此功能调用正在进行完整巡视的工厂,包括在用户设备上下载所需的每个部分的图像路径。 downloadData函数是以下函数:
function downloadData(callback) {
angular.forEach(vm.tourData.parts, function(value, key){
var part = value;
var i = key;
if(part.image !== "") {
TourFactory.getPartImage(part, tourId, function(data){
vm.tourData.parts[i].partImage = data;
console.log('executed with picture ' + i);
});
}
});
if(callback)
callback();
}
不幸的是,forloop本身正在执行同步,但它并没有等待工厂调用完成。我尝试了很多替代承诺,但没有运气。有人可以帮忙吗?我需要等待http调用完成才能从downloadData调用中获得响应。
getPartImage()只是一个例子,每个for循环有五个这样的函数,需要在我在downloadData调用中得到响应之前先完成。
答案 0 :(得分:1)
看看$q.all或here - 它是一个承诺助手函数,可以等待多个承诺完成。它的结果也是一个承诺,所以你可以用其他承诺来链接它。
// Promise function that knows how to download a single part
function downloadPart(myurl) {
// return http promise
return $http({
method: 'GET',
url: myurl
});
};
// Aggregat epromise that downloads all parts
function downloadAllParts(parts) {
var defer = $q.defer(); // Setup return promise
var partsPromises = []; // Setup array for indivudual part promises
angular.forEach(parts, function(part) { // Iterate through each part
// Schedule download of a single
partsPromises.push(downloadPart(part));
});
// Wait for all parts to resolve
$q.all(partsPromises)
.then(function(data) {
// Returned data will be an array of results from each individual http promise
resData = [];
angular.forEach(data, function(partData) {
//handle each return part
resData.push(partData.data);
})
defer.resolve(resData); // Notify client we downloaded all parts
}, function error(response) { // Handle possible errors
console.log('Error while downloading parts'
response);
defer.reject('Error while downloading parts');
});
return defer.promise;
};
然后,在您的客户端中,您只需等待downloadAllParts完成:
downloadAllParts(myParts)
.then(function(data) {
alert('Success!');
}, function(error) {
alert(error);
})
因为$ q.all也是一个承诺,你可以一起摆脱延迟:
// Aggregat epromise that downloads all parts
function downloadAllParts(parts) {
var partsPromises = []; // Setup array for indivudual part promises
angular.forEach(parts, function(part) { // Iterate through each part
// Schedule download of a single
partsPromises.push(downloadPart(part));
});
// Wait for all parts to resolve
return $q.all(partsPromises)
.then(function(data) {
// Returned data will be an array of results from each individual http promise
var resData = [];
angular.forEach(data, function(partData) {
//handle each return part
resData.push(partData.data);
})
return resData;
});
};
这是一个有效的jsfiddle:link