Como fazer o jQuery esperar até que um efeito seja concluído?

107

Tenho certeza de que li sobre isso outro dia, mas não consigo encontrar em lugar nenhum.
Eu tenho um fadeOut()evento após o qual removo o elemento, mas jQuery está removendo o elemento antes que ele tenha a chance de terminar o esmaecimento.
Como faço para que o jQuery espere até que o elemento desapareça e o remova?

uriDium
fonte

Respostas:

167

Você pode especificar uma função de retorno de chamada:

$(selector).fadeOut('slow', function() {
    // will be called when the element finishes fading out
    // if selector matches multiple elements it will be called once for each
});

Documentação aqui .

Paolo Bergantino
fonte
Bingo. Achei que fosse isso, mas o que eu precisava fazer era colocar toda a minha função lá, não apenas a parte de remoção. PS Se alguém estiver interessado, o livro que li e agora encontrei novamente é Learning JQuery - Better Interaction and Design. Obrigado mais uma vez
uriDium
Se alguém tinha um jQuery antigo, esse bug de "callback de animação feita" era desagradável: bugs.jquery.com/ticket/5684
JustAMartin
178

Com a versão jQuery 1.6 você pode usar o .promise()método.

$(selector).fadeOut('slow');
$(selector).promise().done(function(){
    // will be called when all the animations on the queue finish
});
Reinaldo Junior
fonte
4
Isso é redundante para a maioria das animações jQuery, pois há args de retorno de chamada na maioria dos métodos, mas usando promise()ou when()e done()você pode aproveitar alguns comportamentos muito legais de métodos de terceiros ou até mesmo os seus próprios. 1 para significado .promise()!
stuartc
4
Não ouvi isso antes, só salvei minha bunda.
prismspecs
1
no meu caso, estava tentando acessar a animação atual de um elemento que estava acontecendo em outro lugar no meu código e, portanto, não tive acesso ao seu retorno de chamada. +1
Kristian
11
Usar a promessa () também permite que você configure um único retorno de chamada para quando tudo estiver pronto. Se você chamar fadeOut () em um conjunto de 10 coisas, haverá um retorno de chamada para cada coisa com 'this' definido para o escopo apropriado. Se você deseja disparar apenas uma vez, esta função é muito útil. Além disso: Se você animar em um seletor que resulta em zero elementos, o retorno de chamada normal nunca será acionado. Promise () irá disparar no final, não importa o quê.
zslayton
6
Você também pode encadear assim:$(selector).fadeOut('slow').promise().done(function(){...});
Syclone
9

Você também pode $.when()esperar até o promisefinal:

var myEvent = function() {
    $( selector ).fadeOut( 'fast' );
};
$.when( myEvent() ).done( function() {
    console.log( 'Task finished.' );
} );

Caso você esteja fazendo uma solicitação que também pode falhar, você pode até mesmo dar um passo adiante:

$.when( myEvent() )
    .done( function( d ) {
        console.log( d, 'Task done.' );
    } )
    .fail( function( err ) {
        console.log( err, 'Task failed.' );
    } )
    // Runs always
    .then( function( data, textStatus, jqXHR ) {
        console.log( jqXHR.status, textStatus, 'Status 200/"OK"?' );
    } );
Kaiser
fonte
2
Esta parte desta resposta usando $.when()não funciona porque myEvent()não retorna uma promessa e $.when()espera que você cumpra uma ou mais promessas para que ele cumpra seu dever.
jfriend00
6

se for algo que você deseja trocar, esmaecendo um e esmaecendo outro no mesmo lugar, você pode colocar um atributo {position: absolute} nos divs, para que ambas as animações sejam reproduzidas uma em cima da outra, e você não terá esperar que uma animação termine antes de iniciar a próxima.

Samin
fonte