如何在forEach

时间:2015-06-17 03:30:11

标签: javascript angularjs cordova ionic-framework promise

我有一系列图像,我会迭代并将每个图像上传到远程服务器。上传文件后,我使用结果获取文件名并推送到另一个数组。

我遇到的问题是并非所有结果都被推送到阵列。我试图构建一个包含所有上传图像结果的数组。以下代码在lastTask循环结束之前执行forEach

    /**
     * Upload picture
     */
    $scope.upload = function () {

      var token = window.localStorage.getItem('yourTokenKey');
      var defer = $q.defer();
      var promises = [];

      var options = {
        fileKey: "image",
        fileName: " test.png",
        chunkedMode: true,
        mimeType: "image/png",
        headers: {'x-auth-token': token}
      };

      function lastTask() {
        alert(promises);
        $scope.images = [];
        $scope.hide();
        $scope.showAlert();
        $scope.putQc();
        alert('finish').then(function () {
          defer.resolve();
        });
      }

      angular.forEach($scope.images, function (image) {
        $cordovaFileTransfer.upload("http://server.com/file/upload", image, options).then(function (result) {
          // Success!
          promises.push(result.response + '.jpg');
          alert(JSON.stringify(result));
          console.log("SUCCESS: " + JSON.stringify(result.response));
          // Error
        }, function (err) {
          alert(JSON.stringify(err));
          console.log("ERROR: " + JSON.stringify(err));
          // constant progress updates
        }, function (progress) {
          $scope.show();
        });
      });

      $q.all(promises).then(lastTask);

      return defer;
};

2 个答案:

答案 0 :(得分:3)

如果我是正确的,那么您的promises数组是问题所在,而不是推送来自$cordovaFileTransfer.upload的承诺,而是推送您获得的结果字符串

第二个问题,我认为你所做的是承诺anti-pattern,这里不需要$q.defer()

(第三,可能是无关紧要的,JSON.stringify并非真正需要,并希望alert由您定义)

我会把它重写为:

/**
 * Upload picture
 */
$scope.upload = function () {

  var token = window.localStorage.getItem('yourTokenKey');
  var promises = [], results;   //CHANGED

  var options = {
    fileKey: "image",
    fileName: " test.png",
    chunkedMode: true,
    mimeType: "image/png",
    headers: {'x-auth-token': token}
  };

  function lastTask() {
    alert(results);   //CHANGED
    $scope.images = [];
    $scope.hide();
    $scope.showAlert();
    $scope.putQc();
    return alert('finish');   //CHANGED
  }

  promises = $scope.images.map(function (image) {   //CHANGED
    return $cordovaFileTransfer.upload("http://server.com/file/upload", image, options).then(function (result) {   //CHANGED
      // Success!
      results.push(result.response + '.jpg');   //CHANGED
      alert(JSON.stringify(result));
      console.log("SUCCESS: " + JSON.stringify(result.response));
      // Error
    }, function (err) {
      alert(JSON.stringify(err));
      console.log("ERROR: " + JSON.stringify(err));
      throw err;
      // constant progress updates
    }, function (progress) {
      $scope.show();
    });
  });

  return $q.all(promises).then(lastTask);   //CHANGED

};

答案 1 :(得分:2)

问题是你没有将promises推送到你的promise数组中。您(最终)将正常值推送到数组中,但在您在空数组或近空数组上运行$q.all之前不会。

$scope.upload = function() {

    var token = window.localStorage.getItem('yourTokenKey');
    var promises = [];

    var options = {
        fileKey: "image",
        fileName: " test.png",
        chunkedMode: true,
        mimeType: "image/png",
        headers: {
            'x-auth-token': token
        }
    };

    function lastTask(results) {
        alert(results);
        $scope.images = [];
        $scope.hide();
        $scope.showAlert();
        $scope.putQc();
        return results; // keeping the promise chain useful
    }

    angular.forEach($scope.images, function(image) {
        var promiseForUpload = $cordovaFileTransfer.upload("http://server.com/file/upload", image, options).then(function(result) {
            console.log("SUCCESS: " + JSON.stringify(result.response));
            return result.response + '.jpg'; // this will be the promised value
        }, function(err) {
            console.log("ERROR: " + JSON.stringify(err));
            throw err; // re-throwing the error so the q.all promise is rejected
        }, function(progress) {
            $scope.show();
        });
        promises.push(promiseForUpload);
    });

    return $q.all(promises).then(lastTask); // returns a promise for results

};

老实说,虽然我会彻底摆脱中级的东西:

$scope.upload = function() {

    var token = window.localStorage.getItem('yourTokenKey');

    var options = { /* stuff */ };

    function lastTask(results) { // I wouldn't bake this into the $scope.upload, but do it as a result of calling $scope.upload (i.e. with .then).
        alert(results);
        $scope.images = [];
        $scope.hide();
        $scope.showAlert();
        $scope.putQc();
        return results; // keeping the promise chain useful
    }

    var promises = $scope.images.map(function(image){
        return $cordovaFileTransfer.upload("http://server.com/file/upload", image, options);
    });

    return $q.all(promises).then(lastTask); // returns a promise for results

};

最后,如果该函数应该返回一个promise,那么无论在哪里使用它都要确保添加错误处理(例如在链的末尾加.catch)。如果这个函数应该是promise链的末尾(例如,只是通过按钮点击触发而没有任何内容正在侦听响应),那么你需要将catch添加到$q.all(promises).then(lastTask)的末尾。不要发生无声错误。