Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

simple jQuery Chaining insight

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!

like image 591
beeudoublez Avatar asked Feb 06 '12 03:02

beeudoublez


1 Answers

You 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 completed. 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 completion 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 completion 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.net/jfriend00/3Hg6G/

like image 170
jfriend00 Avatar answered Sep 28 '22 09:09

jfriend00