192

在 jQuery 中,是否可以在调用(或任何其他类型的迭代回调)完成调用回调触发事件.each()

例如,我想完成这个“淡入淡出”

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

在进行一些计算$(parentSelect). 如果现有元素仍然对 jQuery 可见并且休眠/延迟任意时间量(每个元素 200 时间)似乎充其量是一个脆弱的解决方案,那么我的计算是不正确的。

我可以轻松地.bind()为事件回调提供必要的逻辑,但我不确定.trigger()在上述迭代完成后如何干净地调用。显然,我不能在迭代中调用触发器,因为它会触发多次。

在 的情况下$.each(),我考虑在 data 参数的末尾添加一些东西(我会在迭代正文中手动查找),但我不想被迫这样做,所以我希望还有其他一些优雅的关于迭代回调控制流程的方法。

4

12 回答 12

192

可能为时已晚,但我认为这段代码有效......

$blocks.each(function(i, elm) {
 $(elm).fadeOut(200, function() {
  $(elm).remove();
 });
}).promise().done( function(){ alert("All was done"); } );
于 2012-01-20T12:17:12.500 回答
170

@tv 答案的替代方案:

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

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

请注意,.each()它本身是同步的——调用之后的语句.each()将仅在.each()调用完成后执行。但是,在迭代中开始的异步操作.each()当然会以它们自己的方式继续进行。这就是这里的问题:淡化元素的调用是计时器驱动的动画,并且它们按照自己的节奏继续。

因此,上面的解决方案会跟踪有多少元素正在褪色。每次调用.fadeOut()都会获得一个完成回调。当回调注意到它已通过所有涉及的原始元素进行计数时,可以确信所有淡入淡出都已完成,从而采取一些后续操作。

这是一个四年前的答案(在 2014 年的这个时间点)。执行此操作的现代方法可能涉及使用 Deferred/Promise 机制,尽管上述方法很简单并且应该可以正常工作。

于 2010-03-01T19:09:51.413 回答
156

好的,这可能是事后的一点,但 .promise() 也应该实现你所追求的。

承诺文件

我正在做的一个项目的一个例子:

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

:)

于 2011-12-21T02:17:05.773 回答
28

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

于 2010-03-01T20:05:28.523 回答
6

我正在使用这样的东西:

$.when(
           $.each(yourArray, function (key, value) {
                // Do Something in loop here
            })
          ).then(function () {
               // After loop ends.
          });
于 2020-04-20T09:17:17.360 回答
5

我发现了很多处理数组但不是 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

于 2011-03-01T17:15:56.660 回答
1

如果你愿意做几个步骤,这可能会奏效。不过,这取决于按顺序完成的动画。我不认为这应该是一个问题。

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

elems.each( function(i) {
    $(this).fadeOut(200, function() { 
        $(this).remove(); 
        if (i == lastID) {
           doMyThing();
        }
    });
});
于 2010-03-01T19:02:24.907 回答
0

您必须将其余的请求排入队列才能使其正常工作。

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;});
        }
    });
});
于 2010-12-21T19:04:17.690 回答
0

关于什么

$(parentSelect).nextAll().fadeOut(200, function() { 
    $(this).remove(); 
}).one(function(){
    myfunction();
}); 
于 2010-03-01T20:33:42.263 回答
0

也许是迟到的回应,但有一个包可以处理这个 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');
    });
于 2018-06-21T11:25:42.000 回答
0

我遇到了同样的问题,我用类似以下代码的解决方案解决了:

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

});

该解决方案解决了以下问题:使用 Deferred 对象同步在 .each() 迭代中启动的异步操作。

于 2017-03-05T09:42:11.123 回答
0
var count = $(parentSelect).length;

$(parentSelect).each(function () {

   //do you task here

   if (!--count) {

     //do the cleanup task

     alert ('Reached the end of each loop')
   }

});
于 2022-03-04T08:51:50.767 回答