Czekać na wszystkie obietnice do rozwiązania

Więc mam sytuację, w której mam wiele łańcuchów obietnic o nieznanej długości. Chcę wykonać jakąś akcję, gdy wszystkie łańcuchy zostaną przetworzone. Czy to w ogóle możliwe? Oto przykład:

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);
});

W tym przykładzie ustawiłem $q.all() dla obietnic 1, 2 i 3, które zostaną rozwiązane w jakimś losowym czasie. Następnie dodaję obietnice na końcu 1 i 3. Chcę, aby all rozwiązał się, gdy wszystkie łańcuchy zostaną rozwiązane. Oto wyjście, gdy uruchamiam to kod:

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

Czy jest sposób, aby poczekać, aż łańcuchy się rozwiążą?

Author: Bergi, 2014-02-13

5 answers

Chcę, aby wszystko zostało rozwiązane, gdy wszystkie łańcuchy zostaną rozwiązane.

Jasne, więc po prostu przekaż obietnicę każdego łańcucha do all() zamiast początkowych obietnic:

$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");
});
 150
Author: Bergi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-04 16:24:31

Zaakceptowana odpowiedź jest prawidłowa. Chciałbym podać przykład, aby rozwinąć go nieco dla tych, którzy nie są zaznajomieni z promise.

Przykład:

W moim przykładzie muszę zastąpić src atrybuty znaczników img różnymi lustrzanymi adresami URL, jeśli są dostępne przed renderowaniem zawartości.

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.
);

Explanation:

From AngularJS docs :

Metoda then:

Then (successCallback, errorCallback, notifyCallback) - niezależnie od tego, kiedy obietnica została lub zostanie rozwiązana lub odrzucona, następnie wywołuje jeden z zakończonych sukcesem lub błędem wywołań zwrotnych asynchronicznie, gdy tylko wynik jest dostępny. Wywołania są wywoływane przez pojedynczy argument: wynik lub powód odrzucenia.

$q. all (promises)

Łączy wiele obietnic w jedną obietnicę, która jest rozwiązywana, gdy wszystkie obietnice wejściowe są rozwiązane.

The promises param może być szeregiem obietnic.

O bind(), Więcej informacji tutaj: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

 15
Author: Hieu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:14

Ostatnio miałem ten problem, ale z niewiadomą liczbą obietnic.Rozwiązane przy użyciu 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
Author: SoniCue,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-18 10:46:13
 0
Author: Nikola Yovchev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-13 16:12:43

Możesz użyć " wait "w"funkcji asynchronicznej" .

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

Uwaga: nie jestem w 100% pewien, że można wywołać funkcję asynchroniczną z funkcji nie-asynchronicznej i mieć odpowiednie wyniki.

To powiedziało, że to nigdy nie będzie używane na stronie internetowej. Ale do testowania obciążenia/testu integracji...może.

Przykładowy kod:

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
Author: Flavouski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-28 17:22:19