在转到下一个对象后,让angular.forEach等待承诺

时间:2015-03-11 09:58:05

标签: javascript angularjs foreach promise angular-promise

我有一个对象列表。对象将传递给延迟函数。我想在解析前一个调用后才调用具有下一个对象的函数。我有什么方法可以做到这一点吗?

angular.forEach(objects, function (object) {
    // wait for this to resolve and after that move to next object
    doSomething(object);
});

7 个答案:

答案 0 :(得分:22)

在ES2017和async/await之前(请参阅下面的ES2017中的选项),如果您想等待承诺,则不能使用.forEach(),因为承诺没有阻止。 Javascript和promises就是这样不行。

  1. 您可以链接多个承诺并使承诺基础设施对它们进行排序。

  2. 只有在前一个承诺完成后,您才能手动迭代并推进迭代。

  3. 您可以使用asyncBluebird这样的库来为您排序。

  4. 有很多不同的选择,但.forEach()不会为你做。


    以下是使用角度承诺的承诺链接进行排序的示例(假设objects是一个数组):

    objects.reduce(function(p, val) {
        return p.then(function() {
            return doSomething(val);
        });
    }, $q.when(true)).then(function(finalResult) {
        // done here
    }, function(err) {
        // error here
    });
    

    并且,使用标准的ES6承诺,这将是:

    objects.reduce(function(p, val) {
        return p.then(function() {
            return doSomething(val);
        });
    }, Promise.resolve()).then(function(finalResult) {
        // done here
    }, function(err) {
        // error here
    });
    

    以下是手动排序的示例(假设objects是一个数组),虽然这不报告完成或错误,如上面的选项所做的那样:

    function run(objects) {
        var cntr = 0;
    
        function next() {
            if (cntr < objects.length) {
                doSomething(objects[cntr++]).then(next);
            }
        }
        next();
    }
    

    <强> ES2017

    在ES2017中,async/wait功能允许您在使用基于非功能的循环(例如forwhile)继续循环迭代之前“等待”履行承诺。 :

    async function someFunc() {
        for (object of objects) {
            // wait for this to resolve and after that move to next object
            let result = await doSomething(object);
        }
    }
    

    代码必须包含在async函数中,然后您可以使用await告诉解释器在继续循环之前等待解析的承诺。请注意,虽然这似乎是“阻塞”类型行为,但它不会阻止事件循环。事件循环中的其他事件仍可在await期间处理。

答案 1 :(得分:9)

是的,您可以使用angular.forEach来实现此目标。

这是一个例子(假设objects是一个数组):

// Define the initial promise
var sequence = $q.defer();
sequence.resolve();
sequence = sequence.promise;

angular.forEach(objects, function(val,key){
    sequence = sequence.then(function() {
        return doSomething(val);
    });
});

以下是如何使用array.reduce完成此操作,类似于@ friend00的答案(假设objects是一个数组):

objects.reduce(function(p, val) {
    // The initial promise object
    if(p.then === undefined) {
        p.resolve(); 
        p = p.promise;
    }
    return p.then(function() {
        return doSomething(val);
    });
}, $q.defer());

答案 2 :(得分:4)

检查角度上的$ q:

function outerFunction() {

  var defer = $q.defer();
  var promises = [];

  function lastTask(){
      writeSome('finish').then( function(){
          defer.resolve();
      });
  }

  angular.forEach( $scope.testArray, function(value){
      promises.push(writeSome(value));
  });

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

  return defer;
}

答案 3 :(得分:2)

最简单的方法是创建一个函数,并在每个promise解析后手动迭代数组中的所有对象。

var delayedFORLoop = function (array) {
    var defer = $q.defer();

    var loop = function (count) {
        var item = array[count];

        // Example of a promise to wait for
        myService.DoCalculation(item).then(function (response) {

        }).finally(function () {
          // Resolve or continue with loop
            if (count === array.length) {
                defer.resolve();
            } else {
                loop(++count);
            }
        });
    }

    loop(0); // Start loop
    return defer.promise;
}

// To use:
delayedFORLoop(array).then(function(response) {
    // Do something
});

我的GitHub上也提供了示例: https://github.com/pietervw/Deferred-Angular-FOR-Loop-Example

答案 4 :(得分:0)

在我提出我自己的解决方案之前尝试上述几种解决方案可能会有所帮助(实际上其他方法没有)

  var sequence;
  objects.forEach(function(item) {
     if(sequence === undefined){
          sequence = doSomethingThatReturnsAPromise(item)
          }else{
          sequence = sequence.then(function(){
               return doSomethingThatReturnsAPromise(item)
                     }); 
                 }
        });

答案 5 :(得分:0)

这对我有用。我不知道这是否是一种正确的方法,但可以帮助减少行数

function myFun(){
     var deffer = $q.defer();
     angular.forEach(array,function(a,i) { 
          Service.method(a.id).then(function(res) { 
               console.log(res); 
               if(i == array.length-1) { 
                      deffer.resolve(res); 
               } 
          }); 
     });
     return deffer.promise;
}

myFun().then(function(res){
     //res here
});

答案 6 :(得分:0)

我使用一种简单的解决方案来连接打印机,该打印机要等到承诺结束后才能转到下一个。

angular.forEach(object, function(data){
    yourFunction(data)
    .then(function (){
        return;
    })
})