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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28983424/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 02:41:38  来源:igfitidea点击:

Make angular.forEach wait for promise after going to next object

javascriptangularjsforeachpromiseangular-promise

提问by Razvan

I have a list of objects. The objects are passed to a deferred function. I want to call the function with the next object only after the previous call is resolved. Is there any way I can do this?

我有一个对象列表。对象被传递给延迟函数。我想仅在解决上一个调用后使用下一个对象调用该函数。有什么办法可以做到这一点吗?

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

回答by jfriend00

Before ES2017 and async/await(see below for an option in ES2017), you can't use .forEach()if you want to wait for a promise because promises are not blocking. Javascript and promises just don't work that way.

在 ES2017 和async/await(见下文ES2017中的一个选项)之前,.forEach()如果你想等待一个承诺,你不能使用,因为承诺没有阻塞。Javascript 和 promise 就不能那样工作。

  1. You can chain multiple promises and make the promise infrastructure sequence them.

  2. You can iterate manually and advance the iteration only when the previous promise finishes.

  3. You can use a library like asyncor Bluebirdthat will sequence them for you.

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

  2. 您可以手动迭代并仅在前一个 Promise 完成时推进迭代。

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

There are lots of different alternatives, but .forEach()will not do it for you.

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



Here's an example of sequencing using chaining of promises with angular promises (assuming objectsis an array):

下面是一个使用 angular promise 链式排序的示例(假设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
});

And, using standard ES6 promises, this would be:

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

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


Here's an example of manually sequencing (assuming objectsis an array), though this does not report back completion or errors like the above option does:

这是手动排序的示例(假设objects是一个数组),尽管这不会像上述选项那样报告完成或错误:

function run(objects) {
    var cntr = 0;

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


ES2017

ES2017

In ES2017, the async/waitfeature does allow you to "wait" for a promise to fulfill before continuing the loop iteration when using non-function based loops such as foror while:

在 ES2017 中,该async/wait功能确实允许您在使用基于非函数的循环(例如foror )时在继续循环迭代之前“等待”履行承诺while

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

The code has to be contained inside an asyncfunction and then you can use awaitto tell the interpreter to wait for the promise to resolve before continuing the loop. Note, while this appears to be "blocking" type behavior, it is not blocking the event loop. Other events in the event loop can still be processed during the await.

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

回答by Bjarni

Yes you can use angular.forEachto achieve this.

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

Here is an example (assuming objectsis an array):

这是一个例子(假设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);
    });
});


Here is how this can be done using array.reduce, similar to @friend00's answer (assuming objectsis an array):

这是如何使用 来完成的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());

回答by bln

check $q on angular:

检查 $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;
}

回答by Peter-Pan

The easiest way is to create a function and manually iterate over all the objects in the array after each promise is resolved.

最简单的方法是创建一个函数并在每个 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
});

Example is also available on my GitHub: https://github.com/pietervw/Deferred-Angular-FOR-Loop-Example

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

回答by Lomithrani

It might help someone as I tried several of above solution before coming up with my own that actually worked for me (the other ones didn't)

它可能对某人有所帮助,因为我在提出自己的解决方案之前尝试了上述几种解决方案,但实际上对我有用(其他解决方案没有)

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

回答by ajay-annie

It worked for me like this. I don't know if it is a right approach but could help to reduce lines

它像这样对我有用。我不知道这是否是正确的方法,但可以帮助减少线条

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
});

回答by mat lav

I use a simple solution for a connection to a printer that wait till the promise is over to go to the next.

我使用一个简单的解决方案连接到打印机,等到承诺结束才能进入下一个。

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