Angularjs循环中的异步调用

时间:2016-01-23 04:02:04

标签: javascript angularjs asynchronous

以下是我在项目中使用的代码,允许用户上传文件。   对于所选的每个文件," $ scope.upload"函数被异步调用。

因为这些是异步调用,所以每次调用都不依赖于之前的调用。

但我的要求是只有在成功回调函数执行后,   然后下一次上传应该发生,因为每次上传都取决于值   由上次上传返回。

请让我知道如何实现。   注意:$ scope.upload是部分角度文件上传js(https://github.com/danialfarid/ng-file-upload

$scope.startUploading = function ($files, errFiles, item) {           

        //$files: an array of files selected
        for (var idx = 0; idx < $files.length; idx++) {
            var $file = $files[idx];


            (function (index) {
                $scope.upload[index] = $upload.upload({
                    url: "../UploadCommentAttachment",
                    method: "POST",
                    file: $file, 
                    data: item 
                }).success(function (responseData, status, headers, config) {

                       item.AuditCommentAttachments.push(responseData);
                       item.CommentId = responseData.CommentId;
                       item.AuditId = responseData.AuditId;
                       item.Operation = "EDIT";
                       item.CommentAttachmentID = responseData.CommentAttachmentID;
                    }

                });
            })(idx);

        }  ///-- for loop end         
    } // startuploading end

3 个答案:

答案 0 :(得分:3)

通用答案

顺序执行异步操作的方法是使用.then方法派生的promise来它们。后续承诺使用的值应在.then方法中返回

function sequentiallyExecute = function (opList) {
    //create initial object
    var passedObject = {};
    passedObject.dataList = [];
    passedObject.response = {};

    //create initial promise
    var promise = $q.when(passedObject);

    //sequentially execute opList
    angular.forEach(opList, function(op) {
        promise.then(function (passedObject) {
            var iPromise = asyncOperation(op, passedObject);
            iPromise.then(function onFulfulled(response) {
                //save response for chaining
                passedObject.response = response;
                //push data to list
                passedObject.dataList.push(response.data);
                //return object for chaining
                return passedObject;
            });
            //return promise for chaining
            return iPromise;
        });
    });

    //return promise to client
    return promise;
};

在客户端代码中,检索最终数据。

(sequentiallyExecute(opList)
).then (function onFulfilled(passedObject) {
    $scope.dataList = passedObject.dataList;
}).catch (function onRejected(error) {
    console.error(error);
});

有关链接的详细信息,请参阅AngularJS $q Service API Reference -- chaining promises

具体答案

不使用.success方法(不可链接),而是使用.then方法( 可链接)。

function asychOperation(op, passedObject) {
    var $file = op.$file
    var item = passedObject.item;

    var httpPromise = $upload.upload({
         url: "../UploadCommentAttachment",
                    method: "POST",
                    file: $file, 
                    data: item 
    });

    var derivedPromise = httpPromise.then(function (response) {
        var data = response.data
        passedObject.dataList.push(data);
        var newItem = {};
        newItem.CommentId = data.CommentId;
        newItem.AuditId = data.AuditId;
        newItem.Operation = "EDIT";
        newItem.CommentAttachmentID = data.CommentAttachmentID;
        passedObject.item = newItem;
    });

    var promise = derivedPromise.then (function onFulfilled() {
        //return object for chaining
        return passedObject;
    });

    //return promise for chaining
    return promise;
};
  

.success服务的.error$http方法已被弃用。而是使用.then.catch方法。

     

有关详细信息,请参阅    AngularJS $http Service API Reference -- deprecation notice

结论

因为调用promise的.then方法会返回一个新的派生promise,所以很容易创建一个promise链。

可以创建任意长度的链,并且由于可以使用另一个承诺(将进一步推迟其解析)来解决承诺,因此可以在链中的任何点暂停/推迟承诺的解析。这使得实现强大的API成为可能。 1

答案 1 :(得分:1)

我已经从ng-file-upload修改了一个小提琴,逐个处理帖子,并使用前一个帖子的响应到当前帖子。请检查my fiddle

这是javascript代码的一部分,可以解决这个问题

function sequentialFileUploadWithReduce(values) {
    var result = ''
    var dfd = $q.defer();

    dfd.resolve();
    return values.reduce(function(currentValue, nextValue, index, values) {
      return Upload.upload({
        url: "https://angular-file-upload-cors-srv.appspot.com/upload",
        method: "POST",
        data: currentValue
      }).then(function(resp) {
        // file is uploaded successfully
        //debugger;
        result += "Uploading file " + index++;
        console.log("Uploading file " + index);
        nextValue.item = resp;
      }, function(resp) {
        // handle error
      }, function(evt) {
        // progress notify
      });
    }, dfd.promise).then(function(responce) {

      return result;
    });
  }

希望这会有所帮助。另请查看控制台和网络选项卡以验证解决方案是否正常工作。

答案 2 :(得分:1)

下面的代码为我完成了所需的工作,顺序执行异步操作,没有链接。

   $scope.startUploading = function ($files, item) 
    {
      var cntr = 0;
      function next() 
      {
          if (cntr < $files.length) 
          {

          $scope.upload[cntr] = $upload.upload({
                                url: "../UploadCommentAttachment",
                                method: "POST",
                                file: $files[cntr],
                                data: item
                            }).then(function (responseData) {                                item.AuditCommentAttachments.push(responseData.data);
                            item.CommentId = responseData.data.CommentId;
                            item.AuditId = responseData.data.AuditId;
                            item.Operation = "EDIT";
                            item.CommentAttachmentID = responseData.data.CommentAttachmentID;
                            cntr++;
                            next();
                        });                    
      }
  }
  next();
}