Invocando una función jQuery después.cada () ha completado


En jQuery, ¿es posible invocar una devolución de llamada o desencadenar un evento después de que se haya completado .each() una invocación de .each() (o cualquier otro tipo de devolución de llamada iterativa) .

Por ejemplo, me gustaría que este" desvanecer y eliminar " para completar

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

Antes de hacer algunos cálculos e insertar nuevos elementos después de $(parentSelect). Mis cálculos son incorrectos si los elementos existentes aún son visibles para jQuery y están inactivos / retrasando una cantidad arbitraria de tiempo (200 para cada elemento) parece como una solución frágil en el mejor de los casos.

Puedo fácilmente .bind() la lógica necesaria para una devolución de llamada de evento, pero no estoy seguro de cómo invocar limpiamente el .trigger() después de que la iteración anterior haya completado . Obviamente, no puedo invocar el disparador dentro de la iteración, ya que se dispararía varias veces.

En el caso de $.each(), he considerado agregar algo al final del argumento de datos (que buscaría manualmente en el cuerpo de la iteración) pero odiaría para ser forzado a eso, así que esperaba que hubiera alguna otra forma elegante de controlar el flujo con respecto a las devoluciones de llamada iterativas.

 162
Author: Khánh, 2010-03-01

10 answers

Una alternativa a la respuesta de @tv:

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

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

Tenga en cuenta que .each()en sí es síncrono - la instrucción que sigue a la llamada a .each() se ejecutará solo después de que se complete la llamada .each(). Sin embargo, las operaciones asíncronas iniciadas en la iteración .each(), por supuesto, continuarán a su manera. Ese es el problema aquí: las llamadas para desvanecer los elementos son animaciones impulsadas por temporizador, y continúan a su propio ritmo.

La solución anterior, por lo tanto, mantiene seguimiento de cuántos elementos se están desvaneciendo. Cada llamada a .fadeOut() recibe una devolución de llamada de finalización. Cuando la devolución de llamada se da cuenta de que se cuenta a través de todos los elementos originales involucrados, algunas acciones posteriores se pueden tomar con la confianza de que todo el desvanecimiento ha terminado.

Esta es una respuesta de hace cuatro años (en este punto en 2014). Una forma moderna de hacer esto probablemente implicaría el uso del mecanismo de Diferido/Promesa, aunque lo anterior es simple y debería funcionar bien.

 146
Author: Pointy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-08 14:12:59

Ok, esto podría ser un poco después del hecho, pero .promise() también debería lograr lo que buscas.

Documentación de la promesa

Un ejemplo de un proyecto en el que estoy trabajando:

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

:)

 152
Author: nbsp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-21 02:17:05

Probablemente sea demasiado tarde, pero creo que este código funciona...

$blocks.each(function(i, elm) {
 $(elm).fadeOut(200, function() {
  $(elm).remove();
 });
}).promise().done( function(){ alert("All was done"); } );
 150
Author: Sébastien GRAVIER,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-20 12:17:12

JavaScript se ejecuta sincrónicamente, por lo que lo que coloque después de each() no se ejecutará hasta que each() esté completo.

Considere la siguiente prueba:

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

Cuando se llama la alerta, count será igual a 1000000 porque la alerta no se ejecutará hasta que each() esté terminada.

 21
Author: user113716,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-08 16:14:06

Encontré muchas respuestas que tratan con matrices pero no con un objeto json. Mi solución fue simplemente iterar a través del objeto una vez mientras se incrementa un contador y luego cuando se itera a través del objeto para realizar su código se puede incrementar un segundo contador. A continuación, simplemente compare los dos contadores juntos y obtenga su solución. Sé que es un poco torpe, pero no he encontrado una solución más elegante hasta ahora. Este es mi código de ejemplo:

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
}

Como dije, no es el muy elegante, pero funciona y funciona bien y todavía no he encontrado una solución mejor.

Saludos, JP

 5
Author: JimP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-01 17:15:56

Si estás dispuesto a hacer un par de pasos, esto podría funcionar. Sin embargo, depende de que las animaciones terminen en orden. No creo que eso sea 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();
        }
    });
});
 1
Author: tvanfosson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-01 19:02:24

¿Qué pasa con

$(parentSelect).nextAll().fadeOut(200, function() { 
    $(this).remove(); 
}).one(function(){
    myfunction();
}); 
 0
Author: Mark Schultheiss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-01 20:33:42

Tienes que poner en cola el resto de tu solicitud para que funcione.

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
Author: Elyx0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-21 19:04:17

Me encuentro con el mismo problema y resolví con una solución como el siguiente código:

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 solución resuelve el siguiente problema: sincronizar las operaciones asíncronas iniciadas en el .cada iteración (), usando objeto diferido.

 0
Author: Roberto AGOSTINO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-06 08:40:11

Tal vez una respuesta tardía, pero hay un paquete para manejar esto 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');
    });
 0
Author: Wim Pruiksma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-21 11:25:42