Ich möchte eine for-Schleife haben, die bei jeder Iteration asynchrone Funktionen aufruft.
Nach der for-Schleife möchte ich einen weiteren Codeblock ausführen, aber nicht bevor alle vorherigen Aufrufe in der for-Schleife aufgelöst wurden.
Mein Problem im Moment ist, dass entweder der Codeblock nach der for-Schleife ausgeführt wird, bevor alle asynchronen Aufrufe beendet sind, oder dass er überhaupt nicht ausgeführt wird.
Der Codeteil mit der FOR-Schleife und dem Codeblock danach (den vollständigen Code finden Sie unter Geige ):
[..]
function outerFunction($q, $scope) {
var defer = $q.defer();
readSome($q,$scope).then(function() {
var promise = writeSome($q, $scope.testArray[0])
for (var i=1; i < $scope.testArray.length; i++) {
promise = promise.then(
angular.bind(null, writeSome, $q, $scope.testArray[i])
);
}
// this must not be called before all calls in for-loop have finished
promise = promise.then(function() {
return writeSome($q, "finish").then(function() {
console.log("resolve");
// resolving here after everything has been done, yey!
defer.resolve();
});
});
});
return defer.promise;
}
Ich habe eine jsFiddle erstellt, die hier zu finden ist: http://jsfiddle.net/riemersebastian/B43u6/3/ .
Im Moment sieht es so aus, als ob die Ausführungsreihenfolge in Ordnung ist (siehe Konsolenausgabe).
Ich vermute, das liegt einfach daran, dass jeder Funktionsaufruf sofort zurückkehrt, ohne echte Arbeit zu leisten. Ich habe versucht, die defer.resolve mit setTimeout zu verzögern, bin jedoch fehlgeschlagen (dh der letzte Codeblock wurde nie ausgeführt). Sie können es im auskommentierten Block in der Geige sehen.
Wenn ich die realen Funktionen verwende, die in eine Datei schreiben und aus einer Datei lesen, wird der letzte Codeblock ausgeführt, bevor der letzte Schreibvorgang abgeschlossen ist, was ich nicht möchte.
Natürlich könnte der Fehler in einer dieser Lese- / Schreibfunktionen liegen, aber ich möchte überprüfen, ob mit dem hier veröffentlichten Code nichts falsch ist.
quelle
Antworten:
Was Sie verwenden müssen, ist $ q.all , das eine Reihe von Versprechen zu einem kombiniert, das nur aufgelöst wird, wenn alle Versprechen gelöst sind.
In Ihrem Fall könnten Sie etwas tun wie:
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.promise; }
quelle
$q.defer().resolve()
wie in jQuery bereit ? Mit anderen Worten, könnten Sie schreibenwriteSome('finish').then(defer.resolve);
? In diesem Fall wäre der Code etwas kompakter, aber ansonsten identisch.Mit dem neuen ES7 können Sie das gleiche Ergebnis viel einfacher erzielen:
let promises = angular.forEach( $scope.testArray, function(value){ writeSome(value); }); let results = await Promise.all(promises); console.log(results);
quelle
angular.forEach()
funktioniert? Wärelet promises = $scope.testArray.map(writeSome);
nicht besser?let results = await Promise.all($scope.testArray.map(writeSome));
ist noch kompakter.Sie können zusammen verwenden
$q
und "reduzieren", um die Versprechen zu verketten.function setAutoJoin() { var deferred = $q.defer(), data; var array = _.map(data, function(g){ return g.id; }); function waitTillAllCalls(arr) { return arr.reduce(function(deferred, email) { return somePromisingFnWhichReturnsDeferredPromise(email); }, deferred.resolve('done')); } waitTillAllCalls(array); return deferred.promise; }
quelle
Dies funktionierte bei mir mit der ES5-Syntax
function outerFunction(bookings) { var allDeferred = $q.defer(); var promises = []; lodash.map(bookings, function(booking) { var deferred = $q.defer(); var query = { _id: booking.product[0].id, populate: true } Stamplay.Object("product").get(query) .then(function(res) { booking.product[0] = res.data[0]; deferred.resolve(booking) }) .catch(function(err) { console.error(err); deferred.reject(err); }); promises.push(deferred.promise); }); $q.all(promises) .then(function(results) { allDeferred.resolve(results) }) .catch(function(err) { allDeferred.reject(results) }); return allDeferred.promise; }
quelle