角度foreach等待http调用的问题

时间:2016-09-16 18:59:48

标签: javascript angularjs promise angular-promise

我正在构建一个离线项目,用户可以在其中进行游览(数据来自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调用中得到响应之前先完成。

1 个答案:

答案 0 :(得分:1)

看看$q.allhere - 它是一个承诺助手函数,可以等待多个承诺完成。它的结果也是一个承诺,所以你可以用其他承诺来链接它。

// 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