Вызов функции jQuery после.каждый () завершил

в jQuery, возможно ли выполнить обратный вызов или событий после обращения .each() (или любой другой тип итеративного обратного вызова) имеет завершено.

например, я хотел бы, чтобы это "исчезает и удаляется" для завершения

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

перед выполнением некоторых вычислений и вставкой новая элементы после $(parentSelect). Мои вычисления неверны, если существующие элементы все еще видны jQuery и sleeping / delaying некоторое произвольное количество времени (200 для каждого элемента) кажется в лучшем случае хрупким решением.

Я могу легко .bind() необходимая логика для обратного вызова события, но я не уверен, как чисто вызвать .trigger() после итерации завершено. Очевидно, что я не могу вызвать триггер внутри итерации, поскольку он будет срабатывать несколько раз.

в случае $.each(), я рассмотрел возможность добавления чего-то в конец аргумент данных (который я бы вручную искал в теле итерации), но я бы не хотел быть вынужденным к этому, поэтому я надеялся, что есть какой-то другой элегантный способ управления потоком в отношении итеративных обратных вызовов.

10 ответов


альтернатива ответу @tv:

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

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

отметим, что и синхронно - заявление, которое следует за вызовом .each() будет выполняться только после .each() вызов завершен. Однако асинхронные операции started на .each() итерация, конечно, будет продолжаться по-своему. Вот в чем проблема: вызовы для затухания элементов-это анимация, управляемая таймером, и они продолжаются самостоятельно шаг.

решение выше, таким образом, отслеживает, сколько элементов исчезают. Каждый вызов .fadeOut() получает обратный вызов завершения. Когда обратный вызов замечает, что он подсчитан через все исходные элементы, некоторые последующие действия могут быть предприняты с уверенностью, что все затухание завершено.

это четырехлетний ответ (на данный момент в 2014 году). Современный способ сделать это, вероятно, будет включать использование механизма отсрочки / обещания, хотя вышеизложенное просто и должно работать просто отлично.


хорошо, это может быть немного после факта, но .promise() также должен достичь того, что вам нужно.

обещать документации

пример из проекта, над которым я работаю:

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

:)


Это, вероятно, поздно, но я думаю, что этот код работает...

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

JavaScript работает синхронно, поэтому все, что вы размещаете после each() не будет работать до each() завершено.

рассмотрим следующий тест:

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

когда оповещение вызывается, количество будет равно 1000000, потому что оповещение не будет работать до each() сделано.


Я нашел много ответов, связанных с массивами, но не с объектом json. Мое решение состояло в том, чтобы просто выполнить итерацию объекта один раз при увеличении счетчика, а затем при итерации объекта для выполнения кода Вы можете увеличить второй счетчик. Затем вы просто сравниваете два счетчика вместе и получаете свое решение. Я знаю, что это немного неуклюже, но я пока не нашел более элегантного решения. Это мой пример кода:

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
}

Как я уже сказал, это не самый элегантный, но он работает, и он работает хорошо, и я еще не нашел лучшего решения.

Ура, JP


Если вы готовы сделать пару шагов, это может сработать. Однако это зависит от завершения анимации в порядке. Я не думаю, что это должно быть проблемой.

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

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

насчет

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

вы должны поставить в очередь остальную часть вашего запроса, чтобы он работал.

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

я сталкиваюсь с той же проблемой, и я решил с решением, как следующий код:

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

});

решение решает следующую задачу: синхронизировать асинхронные операции, запущенные в системе .каждая итерация (), используя отложенный объект.


может быть поздний ответ, но есть пакет для обработки этого 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');
    });