在返回值之前等待forEach完成 - AngularJS

时间:2016-01-31 07:48:27

标签: angularjs file-upload ionic-framework execution

概述: 我正在使用离子框架和AngularJS创建应用程序。该应用程序有2种形式,用户可以上传图像。在第一种形式中,图像上载字段允许仅上载一个图像,而第二图像上载字段允许上载多个图像。在用户上传图像后,我在图像字段下面向用户显示预览。然后用户点击" Save",调用Web Service(定义到工厂)将图像上传到站点。 Service函数实现$ q,因此表单提交只能在上传图像后继续。这很好。

问题: 上传多个图像时,我在控制器中调用另一个辅助函数,循环(forEach)文件数据和每个文件的调用文件保存功能。但是这个辅助函数的执行并不等待forEach循环完成。这允许我获取保存文件的第一个文件详细信息,但不保留保存的文件详细信息。

以下是我用于上传文件的代码:

.controller('AppCtrl', function($q) {
  // Upload single file.
  $scope.fileUpload = function(fileData) {
    var deferred = $q.defer();
    if (angular.isUndefined(fileData) || angular.isUndefined(fileData.dataURL)) {
      deferred.resolve("No new upload found.");
    }
    else {
      var filedata = {
        "file" : {
          file: (fileData.dataURL).replace(/^data:image\/[A-Za-z]{3,4};base64,+/g, ''),
          filename: fileData.file.name,
        },
      };
      AuthServiceContent.uploadNewFile(filedata).then(function(response) {
        deferred.resolve(response);
      }, function(response) {
        deferred.reject(response);
      });
    }
    return deferred.promise;
  };

  // Upload multiple files.
  $scope.fileUploadMultiple = function(data) {
    var deferred = $q.defer();
    var fileUploadStatus = [];
    if (angular.isUndefined(data) || angular.isUndefined(data[0])) {
      deferred.reject("No new upload found.");
    }
    else {
      angular.forEach(data, function(fileData, index) {
        $scope.fileUpload(fileData).then(function(response) {
          fileUploadStatus[index] = response;
        }, function(response) {
        });
      });
    }

    return (!angular.isUndefined(fileUploadStatus) ? deferred.resolve(fileUploadStatus) : deferred.reject(fileUploadStatus));
  };

  $scope.createContent = function(formData) {
    $scope.fileUploadMultiple(formData.image).then(function(response) {
      if (angular.isObject(response)) {
        angular.forEach(response, function(fileData, index) {
          console.log(fileData);
          formData.image.und = [{'fid' : fileData.fid}];
        });
        console.log(formData);
      }
      else {
      }
    }, function(err) {
      console.log("updates failed!!!");
    });
    return;
  };
})

.factory('AuthServiceContent', function($q, $http, DEFAULT) {
  var service_content = {
    uploadNewFile: function(fileData) {
      var deferred = $q.defer();
      $http.post(DEFAULT.serviceURL + 'file', JSON.stringify(fileData), {
        headers : {
          'Content-Type': 'application/json',
          'Cookie': 'cookieData',
        }
      })
      .success(function (data, status, headers, config) {
        deferred.resolve(data);
      })
      .error(function (data, status, headers, config) {
        deferred.reject(data);
      });
      return deferred.promise;
    }
  };

  return service_content;
});

我已经尝试了2天以上并发现了类似的问题,但它没有用。

更新 我通过添加额外的检入循环来实现这一点,这里是控制器中的更新功能,用于上传多个图像。

  $scope.fileUploadMultiple = function(data) {
    var deferred = $q.defer();
    var fileUploadStatus = [];
    if (angular.isUndefined(data) || angular.isUndefined(data[0])) {
      deferred.reject("No new upload found.");
    }
    else {
      var dataLength = (data.length - 1);

      angular.forEach(data, function(fileData, index) {
        $scope.fileUpload(fileData).then(function(response) {
          fileUploadStatus[index] = response;
          // Check if we are at last element. If yes, then return status
          // Return deffered status on last element.
          if (dataLength == index) {
            deferred.resolve(fileUploadStatus);
          }
        }, function(response) {
          // Check if we are at last element. If yes, then return status
          // Return deffered status on last element.
          if (dataLength == index) {
            deferred.reject(fileUploadStatus);
          }
        });
      });
    }

    return deferred.promise;
  };

2 个答案:

答案 0 :(得分:1)

问题在于,您只有一个承诺,并且在第一个调用上传文件返回其结果后立即解析它。

将所有承诺保存在数组中,然后尝试$ q.all:

var promises = [];
angular.forEach(data, function(fileData, index) {
    promises.push($scope.fileUpload(fileData));
});

$q.all(promises).then(function(results) {
   // loop through the results, one for each promise, and do what you need
})

或只返回$q.all(promises)并让应用程序代码处理结果。

$ q.all的一个大问题是,如果任何承诺被拒绝,它只会给出错误。如果你仍然想要处理每个promise的结果,我使用$ q.allSettled的实现(我想我使用this implementation。这会返回每个promise的响应 - 成功或失败 - 带有错误消息或返回的数据,以便我可以单独处理每个承诺的结果。

希望这有帮助

答案 1 :(得分:0)

答案中的更新代码无效。如果最后一个文件是最小的,它会在上传后立即触发 resolve 。我使用的是fileIsUplaoded计数器。

  $scope.fileUploadMultiple = function(data) {
    var deferred = $q.defer();
    var fileUploadStatus = [];
    if (angular.isUndefined(data) || angular.isUndefined(data[0])) {
      deferred.reject("No new upload found.");
    }
    else {
      var uploadCount = data.length;

      angular.forEach(data, function(fileData, index) {
        $scope.fileUpload(fileData).then(function(response) {
          // if a file is uploaded reduce the uploadCount by 1
          uploadCount --;
          fileUploadStatus[index] = response;
          // Check if we are at last element. If yes, then return status
          // Return deffered status on last element.
          if (uploadCount == 0) {
            deferred.resolve(fileUploadStatus);
          }
        }, function(response) {
          // if a file is not uploaded reduce the uploadCount by 1
          uploadCount --;
          // Check if we are at last element. If yes, then return status
          // Return deffered status on last element.
          if (uploadCount == 0) {
            deferred.reject(fileUploadStatus);
          }
        });
      });
    }

    return deferred.promise;
  };