.Each () tamamlandıktan sonra jQuery işlevini çağırma


183

JQuery olarak, mümkün olan bir geri çağırmak veya bir olay tetikleyici bir çağırma sonra .each()(veya tekrar yinelemeli geri arama herhangi bir başka tipi) tamamlandı .

Örneğin, bu "solmaya ve kaldır" ı tamamlamak istiyorum

$(parentSelect).nextAll().fadeOut(200, function() {
    $(this).remove();
});

Bazı hesaplamalar yapıyor ve takmadan önce yeni sonra unsurları $(parentSelect). Mevcut elemanlar hala jQuery tarafından görülebiliyorsa ve rastgele bir süre uyuyor / geciktiriyorsa (her eleman için 200) en iyi ihtimalle kırılgan bir çözüm gibi görünüyor.

.bind()Bir olay geri çağırma için gerekli mantığı kolayca yapabilirim , ancak .trigger()yukarıdaki yineleme tamamlandıktan sonra temiz bir şekilde nasıl çağrılacağından emin değilim . Açıkçası, yinelemenin içindeki tetikleyiciyi birçok kez ateşleyeceği için çağıramıyorum.

Durumunda, $.each()veri argümanının sonuna bir şey eklemeyi düşündüm (yineleme gövdesinde manuel olarak arardım) ama buna zorlanmaktan nefret ederim, bu yüzden başka zarifler olmasını umuyordum yinelemeli geri çağrılara göre akışı kontrol etmenin yolu.


1
Bunu bitirmek istediğiniz ".each ()" ın kendisi değil, ".each ()" çağrısı tarafından başlatılan tüm animasyonlar doğru mu?
Sivri

Bu iyi bir nokta. Bu özel soruyla, evet, ben esas olarak ".each ()" in kendisinin tamamlanmasıyla ilgileniyorum ... ama bence başka bir geçerli soru daha soruyorsun.
Luther Baker

Yanıtlar:


161

@ Tv'nin cevabına bir alternatif:

var elems = $(parentSelect).nextAll(), count = elems.length;

elems.each( function(i) {
  $(this).fadeOut(200, function() { 
    $(this).remove(); 
    if (!--count) doMyThing();
  });
});

.each()Kendisinin senkronize olduğunu unutmayın - çağrıyı izleyen ifade .each()yalnızca .each()çağrı tamamlandıktan sonra yürütülür . Ancak, asenkron işlemleri başlatılmış içinde .each()yineleme elbette kendi yöntemleriyle devam edecektir. Burada sorun bu: öğeleri solmaya yönelik çağrılar zamanlayıcı odaklı animasyonlar ve bunlar kendi hızlarında devam ediyor.

Bu nedenle yukarıdaki çözüm, kaç öğenin soluk olduğunu izler. Her çağrı .fadeOut()tamamlandığında geri arama alır. Geri arama, ilgili tüm orijinal öğeler arasında sayıldığını fark ettiğinde, tüm solmanın sona erdiği konusunda daha sonra bazı önlemler alınabilir.

Bu dört yaşında bir cevaptır (2014'te bu noktada). Bunu yapmanın modern bir yolu muhtemelen, Ertelenmiş / Promise mekanizmasını kullanmayı içerir, ancak yukarıdaki basittir ve iyi çalışmalıdır.


4
Ben geri sayım beri mantıksal olumsuzlama (--count == 0) yerine 0 ile karşılaştırma yapmak istiyorum, ben bu değişikliği seviyorum. Bana göre, aynı etkiye sahip olsa da, amacı daha net hale getiriyor.
tvanfosson

Anlaşıldığı gibi, soruya ilk yorumunuz açıktı. Ben .each () hakkında soruyordum ve istediğim şey olduğunu düşündüm ama siz ve tvanfosson ve şimdi patrick işaret ettiği gibi - aslında ilgilendiğim son solukluktu. Sanırım hepimiz sizin örneğinize katılıyoruz (bunun yerine dizinleri) muhtemelen en güvenli olanıdır.
Luther Baker

@ A.DIMO Ne demek "çok karmaşık"? Hangi kısım karmaşık?
Sivri

169

Muhtemelen geç ama bence bu kod işe yarıyor ...

$blocks.each(function(i, elm) {
 $(elm).fadeOut(200, function() {
  $(elm).remove();
 });
}).promise().done( function(){ alert("All was done"); } );

156

Tamam, bu gerçekten biraz sonra olabilir, ancak .promise () de peşinde olduğunuz şeyi başarmalıdır.

Vaat belgeleri

Üzerinde çalıştığım bir projeden bir örnek:

$( '.panel' )
    .fadeOut( 'slow')
    .promise()
    .done( function() {
        $( '#' + target_panel ).fadeIn( 'slow', function() {});
    });

:)


8
.promise () .each () üzerinde mevcut değildir
Michael Fever

25

JavaScript eşzamanlı olarak çalışır, bu nedenle daha sonra yerleştirdiğiniz her şey tamamlanana each()kadar çalışmaz each().

Aşağıdaki testi düşünün:

var count = 0;
var array = [];

// populate an array with 1,000,000 entries
for(var i = 0; i < 1000000; i++) {
    array.push(i);
}

// use each to iterate over the array, incrementing count each time
$.each(array, function() {
    count++
});

// the alert won't get called until the 'each' is done
//      as evidenced by the value of count
alert(count);

Uyarı çağrıldığında sayı 1000000'e eşit olacaktır çünkü uyarı yapılana kadar çalışmaz each().


8
Verilen örnekte sorun, fadeOut'un animasyon kuyruğuna konması ve eşzamanlı olarak çalıştırılmamasıdır. Bir eachanimasyonu kullanır ve her animasyonu ayrı ayrı planlarsanız, her biri bittikten sonra animasyondan sonra etkinliği tetiklemeniz gerekir.
tvanfosson

3
@tvanfosson - Evet, biliyorum. Luther'in başarmak istediklerine göre, çözümünüz (ve Pointy's) doğru yaklaşım gibi görünüyor. Ama Luther'in yorumları gibi ... Safça, elems.each (foo, bar) gibi bir şey arıyorum, burada foo = 'işlev her öğeye uygulanır' ve bar = 'tüm yinelemeler tamamlandıktan sonra geri arama'. ... bunun bir each()sorun olduğu konusunda ısrarcı görünüyor . Bu yüzden bu cevabı karışıma attım.
user113716

Haklısın Patrick. Ben (mis) .each () zamanlamalarımı zamanlama veya kuyrukta olduğunu anladım. FadeOut'u çağırmanın dolaylı olarak beni bu sonuca götürdüğünü düşünüyorum. tvanfosson ve Pointy, her ikisi de fadeOut problemine cevap verdiler (ki gerçekten bundan sonra olduğum şeydi), ancak mesajınız aslında anlayışımı biraz düzeltir. Cevabınız aslında orijinal soruyu en iyi şekilde cevaplarken Pointy ve tvanfosson sormaya çalıştığım soruyu yanıtladı. Keşke iki cevap seçebilseydim. 'Bu cevabı karışıma attığın' için teşekkürler :)
Luther Baker

@ user113716 İçindeki işlevlerin eachdaha önce çağrılmasının garanti edilmediğini düşündüm alert. beni bu konudaki okumayı açıklayabilir veya gösterebilir misiniz?
Maciej Jankowski

5

Dizilerle ilgili pek çok yanıt buldum ama json nesnesiyle değil. Benim çözümüm basitçe bir sayacı arttırırken nesne boyunca bir kez yinelemek ve sonra kodunuzu gerçekleştirmek için nesne üzerinden yineleme yaparken ikinci bir sayacı artırabilirsiniz. Sonra iki sayacı birlikte karşılaştırır ve çözümünüzü alırsınız. Biraz karmaşık olduğunu biliyorum ama şimdiye kadar daha şık bir çözüm bulamadım. Bu benim örnek kodum:

var flag1 = flag2 = 0;

$.each( object, function ( i, v ) { flag1++; });

$.each( object, function ( ky, val ) {

     /*
        Your code here
     */
     flag2++;
});

if(flag1 === flag2) {
   your function to call at the end of the iteration
}

Dediğim gibi, en zarif değil, ama işe yarıyor ve iyi çalışıyor ve henüz daha iyi bir çözüm bulamadım.

Şerefe, JP


1
Hayır, bu işe yaramıyor. Tüm .each'leri ve sonra son şeyi ateşler ve her şey aynı anda çalışır. .Each'nize bir setTimeout koymayı deneyin ve hemen bayrağı çalıştırdığını göreceksiniz1 === flag2
Michael Fever

1

Birkaç adım atmak istiyorsanız, bu işe yarayabilir. Yine de animasyonların sırayla bitmesine bağlı. Bunun bir sorun olması gerektiğini düşünmüyorum.

var elems = $(parentSelect).nextAll();
var lastID = elems.length - 1;

elems.each( function(i) {
    $(this).fadeOut(200, function() { 
        $(this).remove(); 
        if (i == lastID) {
           doMyThing();
        }
    });
});

Bu işe yarayacaktır - ancak umduğum gibi değil. Safça, elems.each (foo, bar) gibi bir şey arıyorum, burada her öğeye foo = 'işlevi uygulandı' ve bar = 'tüm tekrarlamalar tamamlandıktan sonra geri arama'. JQuery'nin karanlık bir köşesine rastlayıp karşılaşmadığımızı görmek için soruyu biraz daha zaman vereceğim :)
Luther Baker

AFAIK - "son" animasyon tamamlandığında ve senkronize olmayan bir şekilde çalıştıklarından bunu animasyon geri aramasında yapmanız gerekir. @ Pointy'nin daha iyi yazdıklarımın versiyonunu seviyorum çünkü siparişe bağımlı değil, bunun bir sorun olacağını düşünmüyorum.
tvanfosson

0

ne dersin

$(parentSelect).nextAll().fadeOut(200, function() { 
    $(this).remove(); 
}).one(function(){
    myfunction();
}); 

Bu kesinlikle myfunction () 'i bir kez çağırır (ve beni başka bir jQuery konseptiyle tanıştırır) ama aradığım şey sadece ne zaman çalışacağının değil, ne zaman çalışacağının garantisiydi. Ve Patrick'in de bahsettiği gibi, bu kısım oldukça kolay çıkıyor. Gerçekten ne aradığını son fadeOut mantık koştu sonra bir şey çağırmak için bir yol oldu, ben .one () garanti sanmıyorum.
Luther Baker

Sanırım zincir bunu yapıyor - çünkü ilk kısım son kısımdan önce çalışıyor.
Mark Schultheiss

0

Çalışması için isteğinizin geri kalanını sıraya almanız gerekir.

var elems = $(parentSelect).nextAll();
var lastID = elems.length - 1;

elems.each( function(i) {
    $(this).fadeOut(200, function() { 
        $(this).remove(); 
        if (i == lastID) {
            $j(this).queue("fx",function(){ doMyThing;});
        }
    });
});

0

Ben aynı sorunu karşılamak ve aşağıdaki kod gibi bir çözüm ile çözüldü:

var drfs = new Array();
var external = $.Deferred();
drfs.push(external.promise());

$('itemSelector').each( function() {
    //initialize the context for each cycle
    var t = this; // optional
    var internal = $.Deferred();

    // after the previous deferred operation has been resolved
    drfs.pop().then( function() {

        // do stuff of the cycle, optionally using t as this
        var result; //boolean set by the stuff

        if ( result ) {
            internal.resolve();
        } else {
            internal.reject();
        }
    }
    drfs.push(internal.promise());
});

external.resolve("done");

$.when(drfs).then( function() {
    // after all each are resolved

});

Çözüm, şu sorunu çözer: Ertelenmiş nesneyi kullanarak .each () yinelemesinde başlatılan eşzamansız işlemleri eşitlemek için.


Daha önce bir kapatma braketini kaçırıyorsunuz): drfs.push (internal.promise ()); en azından sanırım önce ..
Michael Fever

0

Belki geç bir yanıt ama bu https://github.com/ACFBentveld/Await ile başa çıkmak için bir paket var

 var myObject = { // or your array
        1 : 'My first item',
        2 : 'My second item',
        3 : 'My third item'
    }

    Await.each(myObject, function(key, value){
         //your logic here
    });

    Await.done(function(){
        console.log('The loop is completely done');
    });

0

Ben böyle bir şey kullanıyorum:

$.when(
           $.each(yourArray, function (key, value) {
                // Do Something in loop here
            })
          ).then(function () {
               // After loop ends.
          });
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.