Richiamo di una funzione jQuery dopo aver completato .each ()

In jQuery, è ansible richiamare una richiamata o triggersre un evento dopo che è stata completata una .each() di .each() (o qualsiasi altro tipo di callback iterativo).

Ad esempio, mi piacerebbe che questo “dissolvenza e rimozione” fosse completato

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

prima di fare alcuni calcoli e inserire nuovi elementi dopo $(parentSelect) . I miei calcoli non sono corretti se gli elementi esistenti sono ancora visibili a jQuery e il sonno / ritardo di una quantità arbitraria di tempo (200 per ciascun elemento) sembra una soluzione fragile al meglio.

Posso facilmente .bind() la logica necessaria per un callback di un evento, ma non sono sicuro di come richiamare in modo pulito il .trigger() dopo che l’iterazione di cui sopra è stata completata . Ovviamente, non posso invocare il trigger all’interno dell’iterazione poiché si attiverebbe più volte.

Nel caso di $.each() , ho preso in considerazione l’aggiunta di qualcosa alla fine dell’argomento dati (che avrei cercato manualmente nel corpo dell’iterazione) ma odio essere costretto a farlo, quindi speravo c’era un altro modo elegante per controllare il stream rispetto ai richiami iterativi.

Un’alternativa alla risposta di @ tv:

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

Si noti che .each() stesso è sincrono – l’istruzione che segue la chiamata a .each() verrà eseguita solo dopo che la chiamata .each() è completa. Tuttavia, le operazioni asincrone avviate .each() continueranno naturalmente a modo loro. Questo è il problema qui: le chiamate a sfumare gli elementi sono animazioni gestite dal timer e quelle continuano al loro ritmo.

La soluzione sopra, quindi, tiene traccia di quanti elementi vengono sbiaditi. Ogni chiamata a .fadeOut() ottiene un callback di completamento. Quando la richiamata rileva che è contata attraverso tutti gli elementi originali coinvolti, alcune azioni successive possono essere prese con sicurezza che tutta la dissolvenza è finita.

Questa è una risposta di quattro anni (a questo punto nel 2014). Un modo moderno per farlo probabilmente implicherebbe l’utilizzo del meccanismo Deferred / Promise, sebbene quanto sopra sia semplice e dovrebbe funzionare bene.

Ok, questo potrebbe essere un po ‘dopo il fatto, ma .promise () dovrebbe anche raggiungere quello che stai cercando.

Promessa di documentazione

Un esempio di un progetto su cui sto lavorando:

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

🙂

Probabilmente è tardi ma penso che questo codice funzioni …

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

JavaScript viene eseguito in modo sincrono, quindi tutto ciò che viene posto dopo each() non verrà eseguito fino a quando each() sarà completo.

Considera il seguente test:

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

Quando viene chiamato l'avviso, il conteggio sarà pari a 1000000 perché l'avviso non verrà eseguito finché non viene eseguito each() .

Ho trovato molte risposte relative agli array ma non a un object JSON. La mia soluzione era semplicemente quella di ripetere l’object una volta mentre si incrementava un contatore e poi, durante l’iterazione attraverso l’object per eseguire il codice, è ansible incrementare un secondo contatore. Quindi devi semplicemente confrontare i due contatori insieme e ottenere la soluzione. So che è un po ‘goffo, ma finora non ho trovato una soluzione più elegante. Questo è il mio codice di esempio:

 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 } 

Come ho detto, non è il più elegante, ma funziona e funziona bene e non ho ancora trovato una soluzione migliore.

Saluti, JP

Se sei disposto a fare un paio di passaggi, questo potrebbe funzionare. Dipende comunque dalle animazioni che finiscono in ordine. Non penso che dovrebbe essere un problema.

 var elems = $(parentSelect).nextAll(); var lastID = elems.length - 1; elems.each( function(i) { $(this).fadeOut(200, function() { $(this).remove(); if (i == lastID) { doMyThing(); } }); }); 

che dire

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

Devi accodare il resto della richiesta affinché funzioni.

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

Ho incontrato lo stesso problema e ho risolto una soluzione simile al seguente codice:

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

La soluzione risolve il seguente problema: sincronizzare le operazioni asincrone avviate nell’iterazione .each (), utilizzando l’object rinviato.

Forse una risposta tardiva, ma c’è un pacchetto per gestire questo https://github.com/ACFBentveld/Await

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