Tüm sözlerin çözülmesini bekleyin


107

Bu nedenle, bilinmeyen uzunlukta birden fazla söz zincirim olduğu bir durum var. Tüm ZİNCİRLER işlendiğinde bazı eylemlerin çalışmasını istiyorum. Bu mümkün mü? İşte bir örnek:

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

Bu örnekte, $q.all()rastgele bir zamanda çözülecek olan bir, iki ve üç sözler için bir belirledim . Sonra bir ve üçün sonuna sözler ekliyorum. İstediğim allbütün zincirleri çözüldüğünde çözmek için. İşte bu kodu çalıştırdığımda çıktı:

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

Zincirlerin çözülmesini beklemenin bir yolu var mı?

Yanıtlar:


161

Tüm zincirler çözüldüğünde hepsinin çözülmesini istiyorum.

Elbette, o zaman her zincirin sözünü all()ilk vaatler yerine yerine geçirin:

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

2
En büyük korkumu doğruladığın için teşekkürler. Şimdi son sözümü almanın bir yolunu bulmalıyım lol.
jensengar

Bununla ilgili sorun nedir? Zincirleriniz dinamik olarak mı inşa edildi?
Bergi

Kesinlikle benim sorunum. Dinamik olarak bir söz zinciri oluşturmaya çalışıyorum, sonra zincir (ler) tamamlandığında bir şeyler yapmak istiyorum.
jensengar

Bize kodunuzu gösterebilir misiniz (belki yeni bir soru sorabilirsiniz)? Çalıştırıldıktan sonra zincire eklenen öğeler var mı Q.all- aksi halde önemsiz mi olmalı?
Bergi

Size kodu göstermeyi çok isterdim ... ama henüz yazmayı bitirmedim, ancak açıklamak için elimden geleni yapacağım. Yapılması gereken "eylemler" listem var. Bu eylemler, kendileriyle ilişkili herhangi bir sayıda alt eylem düzeyine sahip olabilir. Tüm eylemler ve alt eylemleri tamamlandığında bir şeyler yapabilmek istiyorum. Muhtemelen birden fazla $q.alle-posta olacaktır, ancak çözüm sürecini başlattığımda hiçbir yeni eylem / vaat zincirlenmeyecek.
jensengar

16

Kabul edilen cevap doğrudur. Aşina olmayanlara biraz detaylandırmak için bir örnek vermek istiyorum promise.

Misal:

Örneğimde, içeriği oluşturmadan önce varsa etiketlerin srcniteliklerini imgfarklı yansıtma URL'leriyle değiştirmem gerekiyor .

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

Açıklama:

AngularJS belgelerinden :

thenyöntem:

daha sonra (successCallback, errorCallback, notifyCallback) - sözün ne zaman çözümlendiğine veya reddedileceğine bakılmaksızın , sonuç elde edilir edilmez başarı veya hata geri aramalarından birini eşzamansız olarak çağırır. Geri aramalar tek bir argümanla çağrılır : sonuç veya reddetme nedeni.

$ q.all (sözler)

Tüm girdi vaatleri çözüldüğünde çözülen tek bir sözde birden fazla sözü birleştirir.

promisesParam vaat bir dizi olabilir.

Hakkında bind(), Daha fazla bilgi burada: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind


thenYöntemi $q.alliade vaat dizisi sağlanır, böylece dönebilir o dizi ve çağrı thençağırmak yerine dizideki her öğe üzerinde thensize söz eklerken promise_array.
nick

4

Son zamanlarda bu sorun vardı, ancak bilinmeyen vaatlerle . JQuery.map () kullanılarak çözüldü .

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

JQuery.map () değil Array.prototype.map () ( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… ) ama bu yaklaşım işe yarıyor.
Anastasia


0

Bir "eşzamansız işlev" içinde "await" kullanabilirsiniz .

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

NOT: Eşzamansız olmayan bir işlevden eşzamansız bir işlevi çağırıp doğru sonuçları alabileceğinizden% 100 emin değilim.

Bu, bunun bir web sitesinde asla kullanılmayacağını söyledi. Ama yük testi / entegrasyon testi için ... belki.

Örnek 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");

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.