在 .each() 完成后调用 jQuery 函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2358205/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 13:19:38  来源:igfitidea点击:

Invoking a jQuery function after .each() has completed

jqueryeach

提问by Luther Baker

In jQuery, is it possible to invoke a callbackor trigger an eventafter an invocation of .each()(or any other type of iterative callback) has completed.

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

For example, I would like this "fade and remove" to complete

例如,我希望这个“淡入淡出”来完成

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

before doing some calculations and inserting newelements after the $(parentSelect). My calculations are incorrect if the existing elements are still visible to jQuery and sleeping/delaying some arbitrary amount of time (200 for each element) seems like a brittle solution at best.

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

I can easily .bind()the necessary logic to an event callback but I'm not sure how to cleanly invoke the .trigger()after the above iteration has completed. Obviously, I can't invoke the trigger inside the iteration as it would fire multiple times.

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

In the case of $.each(), I've considered adding something to the end of the data argument (that I'd manually look for in the iteration body) but I'd hate to be forced to that so I was hoping there was some other elegant way to control the flow with respect to iterative callbacks.

就 而言$.each(),我已经考虑在 data 参数的末尾添加一些内容(我会在迭代体中手动查找),但我不想被迫这样做,所以我希望有其他一些优雅的控制与迭代回调相关的流程的方法。

采纳答案by Pointy

An alternative to @tv's answer:

@tv 答案的替代方法:

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

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

Note that .each()itself is synchronous— the statement that follows the call to .each()will be executed only after the .each()call is complete. However, asynchronous operations startedin the .each()iteration will of course continue on in their own way. That's the issue here: the calls to fade the elements are timer-driven animations, and those continue at their own pace.

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

The solution above, therefore, keeps track of how many elements are being faded. Each call to .fadeOut()gets a completion callback. When the callback notices that it's counted through all of the original elements involved, some subsequent action can be taken with confidence that all of the fading has finished.

因此,上面的解决方案会跟踪有多少元素正在褪色。每次调用.fadeOut()都会得到一个完成回调。当回调注意到它计算了所有涉及的原始元素时,可以放心地采取一些后续操作,即所有淡入淡出都已完成。

This is a four-year-old answer (at this point in 2014). A modern way to do this would probably involve using the Deferred/Promise mechanism, though the above is simple and should work just fine.

这是一个已有四年历史的答案(此时是 2014 年)。一种现代方法可能会涉及使用 Deferred/Promise 机制,尽管上述方法很简单并且应该可以正常工作。

回答by Sébastien GRAVIER

It's probably to late but i think this code work...

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

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

回答by nbsp

Ok, this might be a little after the fact, but .promise() should also achieve what you're after.

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

Promise documentation

承诺文件

An example from a project i'm working on:

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

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

:)

:)

回答by user113716

JavaScript runs synchronously, so whatever you place after each()will not run until each()is complete.

JavaScript 是同步运行的,所以无论你在后面放置什么,在完成each()之前都不会运行each()

Consider the following 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);

When the alert is called, count will equal 1000000 because the alert won't run until each()is done.

当警报被调用时,计数将等于 1000000,因为警报each()在完成之前不会运行。

回答by JimP

I found a lot of responses dealing with arrays but not with a json object. My solution was simply to iterate through the object once while incrementing a counter and then when iterating through the object to perform your code you can increment a second counter. Then you simply compare the two counters together and get your solution. I know it's a little clunky but I haven't found a more elegant solution so far. This is my example code:

我发现了很多处理数组的响应,但没有处理 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
}

Like I said, it's not the most elegant, but it works and it works well and I haven't found a better solution just yet.

就像我说的,它不是最优雅的,但它很有效,而且效果很好,我还没有找到更好的解决方案。

Cheers, JP

干杯,JP

回答by tvanfosson

If you're willing to make it a couple of steps, this might work. It's dependent on the animations finishing in order, though. I don't think that should be a problem.

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

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

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

回答by Mark Schultheiss

what about

关于什么

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

回答by Elyx0

You have to queue the rest of your request for it to work.

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

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

回答by Roberto AGOSTINO

I meet the same problem and I solved with a solution like the following code:

我遇到了同样的问题,我用如下代码解决了这个问题:

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

});

The solution solves the following problem: to synchronize the asynchronous operations started in the .each() iteration, using Deferred object.

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

回答by Wim Pruiksma

Maybe a late response but there is a package to handle this https://github.com/ACFBentveld/Await

也许反应迟了,但有一个包来处理这个 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');
    });