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


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

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

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

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

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

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

10 162

10 ответов:

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

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

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

отметим, что и синхронно - заявление, которое следует за вызовом .each() будет выполняться только после .each() вызов завершен. Однако асинхронные операции начал на .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
}

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

Ура, ДЖП

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

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