单独处理数组中的多个promise

时间:2014-02-05 16:28:25

标签: javascript angularjs

我有一个函数可以对我的服务器进行Web服务调用并返回一个promises数组。

然而,其中一些呼叫可能有效,而其他呼叫可能无效。我的函数当前设置的方式,如果其中一个失败,它会警告整个事情都失败了。如果我正在拨5个电话,1可能会失败。我需要正确记录,我不知道该怎么做。

理想的响应/日志是:

  1. 呼叫1通过
  2. 呼叫2通过
  3. 通过电话3
  4. 呼叫4失败 - 原因
  5. 呼叫5通过
  6. 现在整个事情将返回“句柄用户操作失败”,因为调用4失败。

    功能:

    var manageGroup = function (add, group, users){
    
        var deffered = $q.defer();
        var arrPromises = [];
        var promiseIndex = arrPromises.length;
        var usersLength = users.length;
        var operation = add ? "AddUserToGroup" : "RemoveUserFromGroup";
        var actionText = add ? "Added: " : "Removed: "
        var actionText2 = add ? " to " : " from "
    
        //Apply operation on selected groups
        for (var i = 0; i < usersLength; i++){
            arrPromises[i] = $().SPServices({
                operation: operation,
                groupName: group.name,
                userLoginName: users[i].domain
            });      
        }
    
        $q.all(arrPromises).then(
            function (){
                //when promises are finsihed
                for (var i = 0; i < usersLength; i++){
                    console.log(actionText + users[i].name + actionText2  + group.name);
                };
                deffered.resolve();
            },
            //function incase of AJAX failure
            function (){
                alert('The handle user operation failed.');
            }
        ) 
        return deffered.promise;      
    }
    

    我尝试单独处理promises而不是使用$ q.all但是现在我没有在日志中获得任何内容:

    我把这部分拿出来了:

    /*$q.all(arrPromises).then(
        function (){
            //when promises are finsihed
            for (var i = 0; i < usersLength; i++){
                console.log(actionText + users[i].name + actionText2  + group.name);
            };
            deferred.resolve();
        },
        //function incase of AJAX failure
        function (){
            alert('The handle user operation failed.');
        }
    ) */
    

    引入了这个:

    for (var i = 0; i<promiseIndex; i++){
        arrPromises[i].then(
            function (){
                console.log(actionText + user[i].name + actionText2 + group.name);
            }
        ),
        function (){
            alert('Failed to add/remove'+  user[i].name + ' to ' + group.name)
        }
    }
    
    $q.all(arrPromises).then(function (){
        deferred.resolve();
    }, function (){
        deferred.reject();
    })
    

3 个答案:

答案 0 :(得分:5)

Q(ng。$ q所依据的)或bluebird有一种方法可以满足您的需求。

对于蓝鸟,你会这样:

var Promise = require('bluebird');

Promise.settle(arrPromises).then(function(promises) {
    promises.forEach(function(p) {
        if (promise.isRejected()) {
            // it's a rejected promise.
        }
        else {
            // it's a resolved promise.
        }
    });
});

对于Q,你会这样:

var Q = require('q');

Q.allSettled(arrPromises).then(function(promises) {
    promises.forEach(function(p) {
        if (p.state === 'fulfilled') {
            // it's a resolved promise.
        }
        else {
            // it's a rejected promise.
        }
    });
});

这两个库的好处在于它们符合Promises / A +规范。这意味着您可以取消。$ q,其中一个,您当前的代码仍然有用。

答案 1 :(得分:4)

似乎您遇到一个ajax调用失败导致all()整体失败的问题。您可以捕获单个AJAX调用的失败,并使用您选择的值解析相应的promise。在这里,我只是使用一个空字符串。

<强> Live demo (click).

请记住,这只是展示这一点的示例代码。

  //store promises to use for all()
  var promises = [];

  //loop for ajax calls
  for (var i=0; i<3; ++i) {
    //new deferred for each call
    var deferred = $q.defer();
    //cache the promise
    promises[i] = deferred.promise;
    //use another function to avoid unwanted variable increment
    makeCall(deferred, i);
  }

  $q.all(promises).then(function(allData) {
    console.log(allData);
  });

  function makeCall(deferred, i) {
    //make the ajax call
    $http.get('file'+i+'.txt').then(function(resp) {
      console.log('Call '+i+' returned.');
        //resolve the promise with ajax data if successful
        deferred.resolve(resp.data);
    }, function() {
      //resolve with something else on failure
      deferred.resolve('');
    });
  }

答案 2 :(得分:1)

  

我试图单独处理承诺而不是使用$ q.all但现在我没有在日志中获得任何内容

当执行回调时,您i变量的值错误<{3}}似乎已经下降了。相反,使用这个:

for (var i = 0; i<promiseIndex; i++) (function(i) {
    arrPromises[i].then(function() {
        console.log(actionText + user[i].name + actionText2 + group.name);
    }, function( ){
        alert('Failed to add/remove'+  user[i].name + ' to ' + group.name)
    });
})(i);

你在then调用中也有不匹配的括号,基本上没有传递错误处理程序。

现在,每个承诺都是单独处理的;然而他们的命令并没有坚持下去。为此,你需要使用某种all,看看@ Florian的回答。


另请注意,没有理由明确使用deffered。只是return $q.all(arrPromises)!手动解决延迟并返回其承诺是繁琐且容易出错的 - 在您的原始代码中,您只是忘记在发生错误时拒绝它。当你已经有了承诺并且可以在它们上面使用组合器时,请不要使用它。