【问题标题】:Wait for forEach to complete before returning value - AngularJS在返回值之前等待 forEach 完成 - AngularJS
【发布时间】:2016-05-08 18:46:56
【问题描述】:

概述: 我正在使用离子框架和 AngularJS 创建一个应用程序。该应用程序有 2 种形式,用户可以上传图像。在第一种形式中,图片上传字段只允许上传一张图片,第二种形式的图片上传字段允许上传多张图片。用户上传图像后,我在图像字段下方向用户显示预览。然后用户点击“保存”,调用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;
  };

【问题讨论】:

  • 我试过你更新的代码。如果您上传多个文件并且最后一个是最小的,它会触发 resolvefileUploadStatus 中没有较大的文件。

标签: angularjs file-upload ionic-framework execution


【解决方案1】:

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

将所有的 Promise 保存在一个数组中,然后尝试 $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 的一个大问题是,如果任何承诺被拒绝,它只会给出错误。如果您仍然想处理每个承诺的结果,我使用 $q.allSettled 的实现(我想我使用this implementation。它返回每个承诺的响应 - 无论是成功还是失败 - 带有错误消息或返回的数据,以便我可以分别处理每个 Promise 的结果。

希望对你有帮助

【讨论】:

  • 感谢 Beartums 的快速回复。我已经尝试过 $q.all()。它没有那么好。让我试试例如。你建议
  • 你能告诉我你使用$q.all时的症状是什么吗?回调函数会触发吗?它接收到的数据是什么?
  • 是的,使用 $q.all 时会调用回调函数,但在循环期间我只收到数组中的第一条记录。为了解决这个问题,我添加了条件来检查当前行是否是最后一行,如果是,那么只有我设置 deferred.resolve()/reject()。
  • 您能否更新问题以显示现在的代码?如果是这样,请在 cmets 中联系我,以便我知道看看
  • 我已经用最新代码更新了问题,在“更新”部分
【解决方案2】:

答案中的更新代码不起作用。如果最后一个文件是最小的,它会在上传后立即触发 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;
  };

【讨论】:

    猜你喜欢
    • 2021-06-20
    • 1970-01-01
    • 2020-04-17
    • 2021-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-22
    • 2020-05-13
    相关资源
    最近更新 更多