I thought I understood the chaining power of jQuery, but now I'm a little confused.
Using the example of fading out a DIV, and then removing it:
By jQuery chaining logic, I should be able to do:
$(this).parent().fadeOut(500).remove();
But instead I have to do this:
$(this).parent().fadeOut(500,function() { $(this).remove(); });
Why is that? Thanks!
I thought I understood the chaining power of jQuery, but now I'm a little confused.
Using the example of fading out a DIV, and then removing it:
By jQuery chaining logic, I should be able to do:
$(this).parent().fadeOut(500).remove();
But instead I have to do this:
$(this).parent().fadeOut(500,function() { $(this).remove(); });
Why is that? Thanks!
Share Improve this question asked Feb 6, 2012 at 3:47 beeudoublezbeeudoublez 1,2421 gold badge12 silver badges27 bronze badges3 Answers
Reset to default 11You can't call .remove()
right away because the .fadeOut()
operation is an asynchronous operation that returns right away (after it just starts the animation), but continues executing via timers. When the .fadeOut()
returns and the next chained operation executes, the animation has only just started - it has not pleted. If you do the .remove()
with normal chaining, you remove it right away before the animation makes any progress.
So, as you have discovered, you have to wait until the pletion callback is called for the animation and then you can remove it.
The one exception to this is additional chained animation calls. You can chain animations because animations are a special case that go into the animation queue. Once an animation has started, subsequent animation calls see that there's already an animation in progress and they go into an internal queue. When the first animation finishes, it checks the animation queue to see if there are more chained animations to start.
Nearly all asynchronous operations in javascript are non-blocking like this. That means that the call to start them is just that - a call to start them. That call then returns right away and the rest of the operation proceeds via timers or other events and subsequent javascript continues executing (including other chained methods). You will only know when the operation is actually done by registering for the pletion callback.
The same is true for ajax operations, loading of images, etc...
You got me thinking about how to make the .remove()
method work through the animation queue. One can in fact do that by creating a new version of remove() like this:
$.fn.fxRemove = function() {
this.queue(function(next) {
$(this).remove();
next();
});
return(this);
}
This form of remove goes in the animation queue and will execute when the animations chained before it are done. So, you could then use:
$(this).parent().fadeOut(500).fxRemove();
There's a working example here: http://jsfiddle/jfriend00/3Hg6G/
You can write a plugin to make it wait for you.
DEMO
$.fn.q = function(fn) {
var that = this, arg = Array.prototype.slice.call(arguments, 1);
return this.queue(function(next) {
that[fn].apply(that, arg);
next();
});
};
usage:
$(this).parent().fadeOut(500).q('remove');
Try it the way:
$(this).parent().fadeOut().delay(500).remove();