オブジェクトのリストがあります。オブジェクトは遅延関数に渡されます。前の呼び出しが解決された後にのみ、次のオブジェクトで関数を呼び出したいです。これを行う方法はありますか?
angular.forEach(objects, function (object) {
// wait for this to resolve and after that move to next object
doSomething(object);
});
ES2017および_async/await
_(ES2017のオプションについては以下を参照)より前では、Promiseがブロックされていないため、Promiseを待機する場合は.forEach()
を使用できません。 Javascriptとpromiseは、そのようには機能しません。
複数のプロミスをチェーンして、プロミスインフラストラクチャにそれらをシーケンスさせることができます。
手動で反復し、前のプロミスが終了したときにのみ反復を進めることができます。
async
やBluebird
のようなライブラリを使用して、それらをシーケンスできます。
多くの異なる選択肢がありますが、.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
_機能により、for
や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);
}
}
_
コードはasync
関数内に含まれる必要があります。その後、await
を使用して、ループを続行する前にプロミスが解決するのを待つようインタープリターに指示できます。これは「ブロック」タイプの動作のように見えますが、イベントループはブロックしていません。イベントループの他のイベントは、await
の間に処理できます。
はい、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());
角度で$ 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;
}
最も簡単な方法は、関数を作成し、各プロミスが解決された後に配列内のすべてのオブジェクトを手動で繰り返すことです。
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
私にとってはこのように機能しました。それが正しいアプローチであるかどうかはわかりませんが、行を減らすのに役立ちます
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
});
私は、約束が終わるまで待って次のプリンタに接続する簡単なソリューションを使用します。
angular.forEach(object, function(data){
yourFunction(data)
.then(function (){
return;
})
})
実際に私のために働いた自分のものを思いつく前に、私は上記の解決策のいくつかを試したときに誰かを助けるかもしれません(他のものはしませんでした)
var sequence;
objects.forEach(function(item) {
if(sequence === undefined){
sequence = doSomethingThatReturnsAPromise(item)
}else{
sequence = sequence.then(function(){
return doSomethingThatReturnsAPromise(item)
});
}
});