Frage angular $ q, Wie mehrere Versprechen innerhalb und nach einer For-Schleife zu ketten


Ich möchte eine for-Schleife haben, die jede Iteration asynchrone Funktionen aufruft.

Nach der for-Schleife möchte ich einen anderen Codeblock ausführen, jedoch nicht bevor alle vorherigen Aufrufe in der for-Schleife aufgelöst wurden.

Mein Problem ist im Moment, dass entweder der Code-Block nach der for-Schleife ausgeführt wird, bevor alle asynchronen Aufrufe beendet wurden oder dass OR überhaupt nicht ausgeführt wird.

Der Codeteil mit der FOR-Schleife und dem Codeblock dahinter (für vollständigen Code siehe bitte 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/rimersebastian/B43u6/3/.

Im Moment scheint die Ausführungsreihenfolge in Ordnung zu sein (siehe Konsolenausgabe).

Meine Vermutung ist, dass dies einfach deshalb ist, weil jeder Funktionsaufruf sofort zurückkehrt, ohne wirkliche Arbeit zu leisten. Ich habe versucht, die defer.resolve mit setTimeout zu verzögern, aber fehlgeschlagen (d. H. Der letzte Codeblock wurde nie ausgeführt). Sie können es in dem überkommenen Block in der Geige sehen.

Wenn ich die realen Funktionen benutze, die in Datei schreiben und aus Datei lesen, wird der letzte Codeblock ausgeführt, bevor der letzte Schreibvorgang beendet ist, was ich nicht will.

Natürlich könnte der Fehler in einer dieser Lese- / Schreibfunktionen liegen, aber ich würde gerne überprüfen, dass mit dem Code, den ich hier gepostet habe, nichts falsch ist.


75
2018-01-09 15:31


Ursprung


Antworten:


Was Sie brauchen, ist $ q.alle was eine Anzahl von Versprechen zu einer verbindet, die 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;
}

118
2018-01-10 23:28



Mit der neuen ES7 können Sie das gleiche Ergebnis viel einfacher erreichen:

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

let results = await Promise.all(promises);

console.log(results);

2
2018-06-01 08:29



Sie können verwenden $q und zusammen "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;
}

0
2018-04-21 13:12



Dies funktionierte für mich 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;
}

0
2017-11-04 01:04