.each ()가 완료된 후 jQuery 함수 호출


183

jQuery에서는 (또는 다른 유형의 반복 콜백) 호출이 완료된콜백호출 하거나 이벤트를 트리거 할 수 있습니다..each()

예를 들어이 "페이드 앤 제거"를 완료하려면

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

일부 계산을 수행 하고 . 뒤에 요소를 삽입하기 전에 $(parentSelect)기존 요소가 여전히 jQuery에 표시되고 임의의 시간 (각 요소 당 200 개)이 잠자기 / 지각되어 있으면 취성 솔루션처럼 보이는 경우 계산이 올바르지 않습니다.

.bind()이벤트 콜백에 필요한 논리를 쉽게 얻을 수 있지만 .trigger()위의 반복이 완료된 후 깨끗하게 호출하는 방법을 모르겠습니다 . 분명히 반복 내에서 트리거가 여러 번 발생하므로 트리거를 호출 할 수 없습니다.

의 경우 $.each(), 나는 데이터 인수의 끝에 무언가를 추가하는 것을 고려했습니다 (반복 본문에서 수동으로 찾을 것입니다). 반복 콜백과 관련하여 흐름을 제어하는 ​​방법.


1
".each ()"자체가 아니라 ".each ()"호출로 시작된 모든 애니메이션이 아니라는 것을 올바르게 이해하고 있습니까?
Pointy

좋은 지적입니다. 이 특정 질문으로 예, 주로 ".each ()"자체의 완성에 대해 우려하고 있지만 다른 실행 가능한 질문을 제기한다고 생각합니다.
루터 베이커

답변:


161

@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()은 완료 콜백 을 받습니다. 콜백이 관련된 모든 원래 요소를 통해 계산 된 것을 알면 모든 페이딩이 완료되었다는 확신을 가지고 후속 조치를 취할 수 있습니다.

이것은 4 살짜리 답변입니다 (2014 년 현재). 이 작업을 수행하는 현대적인 방법은 아마도 지연 / 약속 메커니즘을 사용하는 것과 관련이있을 것입니다. 비록 위의 내용은 간단하고 잘 작동합니다.


4
카운트 다운을하기 때문에 논리적 부정 (--count == 0) 대신 0과 비교하려고하지만이 변경이 마음에 듭니다. 나에게 그것은 같은 효과가 있지만 의도를 명확하게 만듭니다.
tvanfosson

결과적으로, 귀하의 질문에 대한 귀하의 초기 의견이 발견되었습니다. 나는 .each ()에 대해 묻고 있었고 그것이 내가 원하는 것이라고 생각했지만 당신과 tvanfosson과 지금 패트릭은 지적했다. 실제로 관심이있는 것은 마지막 fadeOut이었다. 나는 우리 모두가 당신의 모범에 동의한다고 생각한다. 아마도 가장 안전 할 것입니다.
루터 베이커

@ A.DIMO "너무 복잡하다"는 무슨 뜻입니까? 어떤 부분이 복잡합니까?
Pointy

169

아마 늦었지만이 코드가 작동한다고 생각합니다 ...

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

156

좋아, 이것은 사실 이후 약간이지만, .promise () 또한 당신이 추구하는 것을 달성해야합니다.

약속 문서

내가 작업중 인 프로젝트의 예 :

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

:)


8
.promise ()는 .each ()에서 사용할 수 없습니다
Michael Fever

25

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


8
주어진 예제에서 문제는 fadeOut이 애니메이션 큐에 놓여 동 기적으로 실행되지 않는다는 것입니다. each및 애니메이션을 개별적으로 사용 하고 예약하는 경우 애니메이션이 완료된 후가 아니라 애니메이션 후에도 이벤트를 시작해야합니다.
tvanfosson

3
@tvanfosson-그래, 알아 루터가 달성하고자하는 바에 따르면, 귀하의 솔루션 (및 Pointy 's)은 ​​올바른 접근법처럼 보입니다. 그러나 Luther의 의견에서 ... Naively, 나는 elems.each (foo, bar)와 같은 것을 찾고 있습니다. 여기서 foo = '각 요소에 적용되는 함수'및 bar = '모든 반복이 완료된 후의 콜백'. ... 그것이 each()문제 라는 주장을 꾸준히하는 것 같습니다 . 그래서이 답변을 믹스에 던졌습니다.
user113716

당신은 올바른 패트릭입니다. .each ()가 콜백을 예약하거나 대기열에 넣었다는 것을 이해했습니다. fadeOut을 호출하면 간접적으로 그 결론을 이끌어 냈다고 생각합니다. tvanfosson과 Pointy는 fadeOut 문제에 대한 답변을 제공했지만 (실제로 나왔던 것) 귀하의 게시물은 실제로 내 이해를 약간 수정합니다. Pointy와 tvanfosson이 내가 묻고 자 한 질문에 대답하는 동안 귀하의 답변은 실제로 원래 질문에 가장 잘 대답합니다. 두 가지 답변을 선택할 수 있기를 바랍니다. '이 답변을 믹스에 던지기'주셔서 감사합니다 :)
Luther Baker

@ user113716 내부 함수 each가 이전에 호출되지 않았다고 생각했습니다 alert. 이 글을 읽거나 설명해 주시겠습니까?
Maciej Jankowski

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


1
이 작동하지 않습니다. 모든 .each를 실행 한 다음 마지막 작업을 실행하고 모든 것이 동시에 실행됩니다. .each에 setTimeout을 넣으면 바로 flag1 === flag2가 실행됩니다.
Michael Fever

1

당신이 그것을 두 단계로 만들려고한다면, 이것은 효과가있을 수 있습니다. 그래도 순서대로 애니메이션에 의존합니다. 나는 그것이 문제가 될 것이라고 생각하지 않습니다.

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

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

이 방법은 효과가 있지만 원하는 것은 아닙니다. 순진하게, 나는 foo = '각 요소에 적용되는 함수'와 bar = '모든 반복이 완료된 후의 콜백'과 같은 elems.each (foo, bar)와 같은 것을 찾고 있습니다. 우리가 jQuery의 어두운 구석을 발견했는지 좀 더 많은 시간을 질문 할 것입니다 :)
Luther Baker

AFAIK- "마지막"애니메이션이 완료 될 때 트리거해야하며 비동기식으로 실행되므로 애니메이션 콜백에서 애니메이션을 수행해야합니다. 나는 그것이 문제가 될 것이라고 생각하지 않고 주문에 의존하지 않기 때문에 내가 쓴 것의 @Pointy 버전을 좋아한다.
tvanfosson

0

이건 어떤가요

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

이것은 확실히 myfunction ()을 한 번 호출하고 (다른 jQuery 개념을 소개합니다), 내가 찾고 있던 것은 그것이 한 번 실행될 것이라는 것이 아니라 '언제 언제'실행될 것이라는 보장이었습니다. Patrick이 언급했듯이 그 부분은 매우 쉬운 것으로 판명되었습니다. 내가 정말로 찾고있는 것은 마지막 fadeOut 논리가 실행 된 후 무언가를 호출하는 방법 이었으므로 .one () 보장하지는 않습니다.
Luther Baker

첫 번째 부분이 마지막 부분보다 먼저 실행되기 때문에 체인이 그렇게한다고 생각합니다.
Mark Schultheiss

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

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 () 반복에서 시작된 비동기 작업을 동기화합니다.


전에 닫는 괄호가 없습니다) : drfs.push (internal.promise ()); 적어도 나는 그 전에 생각합니다 ..
Michael Fever

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

0

나는 이와 같은 것을 사용하고있다 :

$.when(
           $.each(yourArray, function (key, value) {
                // Do Something in loop here
            })
          ).then(function () {
               // After loop ends.
          });
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.