webentwicklung-frage-antwort-db.com.de

Warten Sie, bis alle Versprechen erfüllt sind

Ich habe also eine Situation, in der ich mehrere Versprechensketten von unbekannter Länge habe. Ich möchte, dass eine Aktion ausgeführt wird, wenn alle KETTEN verarbeitet wurden. Ist das überhaupt möglich? Hier ist ein Beispiel:

app.controller('MainCtrl', function($scope, $q, $timeout) {
    var one = $q.defer();
    var two = $q.defer();
    var three = $q.defer();

    var all = $q.all([one.promise, two.promise, three.promise]);
    all.then(allSuccess);

    function success(data) {
        console.log(data);
        return data + "Chained";
    }

    function allSuccess(){
        console.log("ALL PROMISES RESOLVED")
    }

    one.promise.then(success).then(success);
    two.promise.then(success);
    three.promise.then(success).then(success).then(success);

    $timeout(function () {
        one.resolve("one done");
    }, Math.random() * 1000);

    $timeout(function () {
        two.resolve("two done");
    }, Math.random() * 1000);

    $timeout(function () {
        three.resolve("three done");
    }, Math.random() * 1000);
});

In diesem Beispiel habe ich eine $q.all() für Versprechen eins, zwei und drei eingerichtet, die zu einem beliebigen Zeitpunkt aufgelöst werden. Ich füge dann Versprechungen an die Enden von eins und drei an. Ich möchte, dass all aufgelöst wird, wenn alle Ketten aufgelöst wurden. Hier ist die Ausgabe, wenn ich diesen Code ausführe:

one done 
one doneChained
two done
three done
ALL PROMISES RESOLVED
three doneChained
three doneChainedChained 

Gibt es eine Möglichkeit zu warten, bis die Ketten aufgelöst sind?

106
jensengar

Ich möchte, dass das All aufgelöst wird, wenn alle Ketten aufgelöst sind.

Sicher, dann übergeben Sie einfach das Versprechen jeder Kette an all() anstelle der ursprünglichen Versprechen:

$q.all([one.promise, two.promise, three.promise]).then(function() {
    console.log("ALL INITIAL PROMISES RESOLVED");
});

var onechain   = one.promise.then(success).then(success),
    twochain   = two.promise.then(success),
    threechain = three.promise.then(success).then(success).then(success);

$q.all([onechain, twochain, threechain]).then(function() {
    console.log("ALL PROMISES RESOLVED");
});
156
Bergi

Die akzeptierte Antwort ist richtig. Ich möchte denjenigen, die mit promise nicht vertraut sind, ein Beispiel geben, um es ein wenig zu erläutern.

Beispiel:

In meinem Beispiel muss ich die src -Attribute von img -Tags vor dem Rendern des Inhalts durch andere Spiegel-URLs ersetzen, sofern diese verfügbar sind.

var img_tags = content.querySelectorAll('img');

function checkMirrorAvailability(url) {

    // blah blah 

    return promise;
}

function changeSrc(success, y, response) {
    if (success === true) {
        img_tags[y].setAttribute('src', response.mirror_url);
    } 
    else {
        console.log('No mirrors for: ' + img_tags[y].getAttribute('src'));
    }
}

var promise_array = [];

for (var y = 0; y < img_tags.length; y++) {
    var img_src = img_tags[y].getAttribute('src');

    promise_array.Push(
        checkMirrorAvailability(img_src)
        .then(

            // a callback function only accept ONE argument. 
            // Here, we use  `.bind` to pass additional arguments to the
            // callback function (changeSrc).

            // successCallback
            changeSrc.bind(null, true, y),
            // errorCallback
            changeSrc.bind(null, false, y)
        )
    );
}

$q.all(promise_array)
.then(
    function() {
        console.log('all promises have returned with either success or failure!');
        render(content);
    }
    // We don't need an errorCallback function here, because above we handled
    // all errors.
);

Erklärung:

From AngularJS docs :

Die then Methode:

then (successCallback, errorCallback, notifyCallback) - ruft unabhängig davon, wann das Versprechen aufgelöst oder abgelehnt wurde oder wird, einen der Erfolgs- oder Fehler-Rückrufe asynchron auf sobald das ergebnis vorliegt. Die Rückrufe werden mit einem einzelnen Argument aufgerufen: dem Ergebnis- oder Ablehnungsgrund.

$ q.all (Versprechen)

Kombiniert mehrere Versprechungen zu einer einzigen Versprechung, die aufgelöst wird, wenn alle Eingabeversprechungen aufgelöst sind.

Der Parameter promises kann eine Reihe von Versprechungen sein.

About bind(), Weitere Informationen hier: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

16
Hieu

Hatte vor kurzem dieses Problem aber mit unbekannter Anzahl von Versprechungen. Gelöst mit jQuery.map () .

function methodThatChainsPromises(args) {

    //var args = [
    //    'myArg1',
    //    'myArg2',
    //    'myArg3',
    //];

    var deferred = $q.defer();
    var chain = args.map(methodThatTakeArgAndReturnsPromise);

    $q.all(chain)
    .then(function () {
        $log.debug('All promises have been resolved.');
        deferred.resolve();
    })
    .catch(function () {
        $log.debug('One or more promises failed.');
        deferred.reject();
    });

    return deferred.promise;
}
3
SoniCue
0
Nikola Yovchev

Sie können "wait" in einer "asynchronen Funktion" verwenden.

app.controller('MainCtrl', async function($scope, $q, $timeout) {
  ...
  var all = await $q.all([one.promise, two.promise, three.promise]); 
  ...
}

HINWEIS: Ich bin nicht zu 100% sicher, dass Sie eine asynchrone Funktion von einer nicht asynchronen Funktion aus aufrufen und die richtigen Ergebnisse erzielen können.

Das heißt, dies würde nie auf einer Website verwendet werden. Aber für Lasttests/Integrationstests ... vielleicht.

Beispielcode:

async function waitForIt(printMe) {
  console.log(printMe);
  console.log("..."+await req());
  console.log("Legendary!")
}

function req() {
  
  var promise = new Promise(resolve => {
    setTimeout(() => {
      resolve("DARY!");
    }, 2000);
    
  });

    return promise;
}

waitForIt("Legen-Wait For It");
0
Flavouski