web-dev-qa-db-ja.com

angular.forEachが次のオブジェクトに移動した後、約束を待つようにします

オブジェクトのリストがあります。オブジェクトは遅延関数に渡されます。前の呼び出しが解決された後にのみ、次のオブジェクトで関数を呼び出したいです。これを行う方法はありますか?

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

ES2017および_async/await_(ES2017のオプションについては以下を参照)より前では、Promiseがブロックされていないため、Promiseを待機する場合は.forEach()を使用できません。 Javascriptとpromiseは、そのようには機能しません。

  1. 複数のプロミスをチェーンして、プロミスインフラストラクチャにそれらをシーケンスさせることができます。

  2. 手動で反復し、前のプロミスが終了したときにのみ反復を進めることができます。

  3. asyncBluebirdのようなライブラリを使用して、それらをシーケンスできます。

多くの異なる選択肢がありますが、.forEach()はあなたのためにそれをしません。


angular promises(objectsが配列であると仮定した場合)を使用したpromiseのチェーンを使用したシーケンスの例は次のとおりです。

_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の間に処理できます。

24
jfriend00

はい、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);
    });
});

@ friend00の答えと同様に、array.reduceを使用してこれを行う方法を次に示します(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());
10
Bjarni

角度で$ 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;
}
4
bln

最も簡単な方法は、関数を作成し、各プロミスが解決された後に配列内のすべてのオブジェクトを手動で繰り返すことです。

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

2
Peter-Pan

私にとってはこのように機能しました。それが正しいアプローチであるかどうかはわかりませんが、行を減らすのに役立ちます

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
});
0
ajay-annie

私は、約束が終わるまで待って次のプリンタに接続する簡単なソリューションを使用します。

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

実際に私のために働いた自分のものを思いつく前に、私は上記の解決策のいくつかを試したときに誰かを助けるかもしれません(他のものはしませんでした)

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